Просмотр исходного кода

add a new Thread implementation, additional work required

mikymod 12 лет назад
Родитель
Сommit
ea4fb28d2f

+ 1 - 0
engine/CMakeLists.txt

@@ -370,6 +370,7 @@ if (LINUX)
 		os/linux/Thread.h
 		os/linux/Mutex.h
 		os/linux/Cond.h
+		os/posix/Semaphore.h
 	)
 
 	list (APPEND OS_SRC

+ 1 - 0
engine/os/linux/Thread.h

@@ -27,3 +27,4 @@ OTHER DEALINGS IN THE SOFTWARE.
 #pragma once
 
 #include "../posix/Thread.h"
+#include "../posix/Thread2.h"

+ 12 - 4
engine/os/posix/Cond.h

@@ -62,25 +62,33 @@ inline Cond::Cond()
 {
 	memset(&m_cond, 0, sizeof(pthread_cond_t));
 
-	pthread_cond_init(&m_cond, NULL);
+	int32_t result = pthread_cond_init(&m_cond, NULL);
+
+	CE_ASSERT(result == 0, "Failed to init cond");
 }
 
 //-----------------------------------------------------------------------------
 inline Cond::~Cond()
 {
-	pthread_cond_destroy(&m_cond);
+	int32_t result = pthread_cond_destroy(&m_cond);
+
+	CE_ASSERT(result == 0, "Failed to destroy cond");
 }
 
 //-----------------------------------------------------------------------------
 inline void Cond::signal()
 {
-	pthread_cond_signal(&m_cond);
+	int32_t result = pthread_cond_signal(&m_cond);
+
+	CE_ASSERT(result == 0, "Failed to signal cond");
 }
 
 //-----------------------------------------------------------------------------
 inline void Cond::wait(Mutex& mutex)
 {
-	pthread_cond_wait(&m_cond, &(mutex.m_mutex));
+	int32_t result = pthread_cond_wait(&m_cond, &(mutex.m_mutex));
+
+	CE_ASSERT(result == 0, "Failed to wait cond");
 }
 
 } // namespace crown

+ 13 - 4
engine/os/posix/Mutex.h

@@ -31,6 +31,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #include "Types.h"
 #include "OS.h"
+#include "Assert.h"
 
 namespace crown
 {
@@ -63,25 +64,33 @@ inline Mutex::Mutex()
 {
 	memset(&m_mutex, 0, sizeof(pthread_mutex_t));
 
-	pthread_mutex_init(&m_mutex, NULL);
+	int32_t result = pthread_mutex_init(&m_mutex, NULL);
+
+	CE_ASSERT(result == 0, "Failed to init mutex");
 }
 
 //-----------------------------------------------------------------------------
 inline Mutex::~Mutex()
 {
-	pthread_mutex_destroy(&m_mutex);
+	int32_t result = pthread_mutex_destroy(&m_mutex);
+
+	CE_ASSERT(result == 0, "Failed to destroy mutex");
 }
 
 //-----------------------------------------------------------------------------
 inline void Mutex::lock()
 {
-	pthread_mutex_lock(&m_mutex);
+	int32_t result = pthread_mutex_lock(&m_mutex);
+
+	CE_ASSERT(result == 0, "Failed to acquire lock");
 }
 
 //-----------------------------------------------------------------------------
 inline void Mutex::unlock()
 {
-	pthread_mutex_unlock(&m_mutex);
+	int32_t result = pthread_mutex_unlock(&m_mutex);
+
+	CE_ASSERT(result == 0, "Failed to release lock");
 }
 
 } // namespace crown

+ 6 - 7
engine/os/posix/Semaphore.h

@@ -28,12 +28,11 @@ OTHER DEALINGS IN THE SOFTWARE.
 
 #include <errno.h>
 #include <semaphore.h>
-#include <time.h>
-#include <pthread.h>
 
 #include "Assert.h"
 #include "Mutex.h"
 #include "Cond.h"
+#include "Log.h"
 
 namespace crown
 {
@@ -42,23 +41,23 @@ class Semaphore
 {
 public:
 
-	Semaphore();
-	~Semaphore();
+			Semaphore();
+			~Semaphore();
 
 	void	post(uint32_t count = 1);
 	void	wait();
 
 private:
 
-	Mutex m_mutex;
-	Cond m_cond;
+	Mutex 	m_mutex;
+	Cond 	m_cond;
+
 	int32_t m_count;
 
 private:
 
 	Semaphore(const Semaphore& s); // no copy constructor
 	Semaphore& operator=(const Semaphore& s); // no assignment operator
-
 };
 
 //-----------------------------------------------------------------------------

+ 167 - 0
engine/os/posix/Thread2.h

@@ -0,0 +1,167 @@
+/*
+Copyright (c) 2013 Daniele Bartolini, Michele Rossi
+Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#pragma once
+
+#include <cstring>
+
+#include "Assert.h"
+#include "Types.h"
+#include "Semaphore.h"
+#include "Log.h"
+
+namespace crown
+{
+
+typedef int32_t (*OsThreadFunction)(void*);
+
+class OsThread
+{
+public:
+
+						OsThread(const char* name);
+						~OsThread();
+
+	void				start(OsThreadFunction func, void* data = NULL, size_t stack_size = 0);
+	void				stop();
+
+	bool				is_running();
+
+private:
+
+	int32_t				run();
+
+	static void* 		thread_proc(void* arg);
+
+private:
+
+	const char* 		m_name;
+
+	pthread_t			m_handle;
+	OsThreadFunction 	m_function;
+	void*				m_data;
+	Semaphore			m_sem;
+	size_t 				m_stack_size;
+
+	bool				m_is_running :1;
+};
+
+//-----------------------------------------------------------------------------
+inline OsThread::OsThread(const char* name) :
+	m_name(name),
+	m_handle(0),
+	m_function(NULL),
+	m_data(NULL),
+	m_stack_size(0),
+	m_is_running(false)
+{
+	memset(&m_handle, 0, sizeof(pthread_t));
+}
+
+//-----------------------------------------------------------------------------
+inline OsThread::~OsThread()
+{
+	if (m_is_running)
+	{
+		stop();
+	}
+}
+
+//-----------------------------------------------------------------------------
+inline void OsThread::start(OsThreadFunction func, void* data, size_t stack_size)
+{
+	CE_ASSERT(!m_is_running, "Thread is already running");
+	CE_ASSERT(func != NULL, "Function must be != NULL");
+
+	m_function = func;
+	m_data = data;
+	m_stack_size = stack_size;
+
+	pthread_attr_t attr;
+	int32_t result = pthread_attr_init(&attr);
+
+	CE_ASSERT(result == 0, "pthread_attr_init failed. errno: %d", result);
+
+	if (m_stack_size != 0)
+	{
+		result = pthread_attr_setstacksize(&attr, m_stack_size);
+		CE_ASSERT(result == 0, "pthread_attr_setstacksize failed. errno: %d", result);
+	}
+
+	result = pthread_create(&m_handle, &attr, thread_proc, this);
+	CE_ASSERT(result == 0, "pthread_create failed. errno: %d", result);
+
+	// Free attr memory
+	result = pthread_attr_destroy(&attr);
+	CE_ASSERT(result == 0, "pthread_attr_destroy failed. errno: %d", result);
+
+	m_is_running = true;
+
+	m_sem.wait();
+}
+
+//-----------------------------------------------------------------------------
+inline void OsThread::stop()
+{
+	CE_ASSERT(m_is_running, "Thread is not running");
+	
+	m_is_running = false;
+
+	int32_t result = pthread_join(m_handle, NULL);
+
+	CE_ASSERT(result == 0, "Thread join failed. errno: %d", result);
+
+	m_handle = 0;
+}
+
+//-----------------------------------------------------------------------------
+inline bool OsThread::is_running()
+{
+	return m_is_running;
+}
+
+//-----------------------------------------------------------------------------
+inline int32_t OsThread::run()
+{
+	m_sem.post();
+	
+	return m_function(m_data);
+}
+
+//-----------------------------------------------------------------------------
+inline void* OsThread::thread_proc(void* arg)
+{
+	OsThread* thread = (OsThread*)arg;
+
+	int32_t result = thread->run();
+
+	CE_ASSERT(result == 0, "Function failed");
+
+	return NULL;
+}
+
+
+} // namespace crown

+ 3 - 0
engine/tests/CMakeLists.txt

@@ -12,6 +12,7 @@ add_executable(paths paths.cpp)
 add_executable(dynamic-strings dynamic-strings.cpp)
 add_executable(json json.cpp)
 add_executable(events events.cpp)
+add_executable(threads threads.cpp)
 
 target_link_libraries(allocators crown)
 target_link_libraries(containers crown)
@@ -21,6 +22,7 @@ target_link_libraries(paths crown)
 target_link_libraries(dynamic-strings crown)
 target_link_libraries(json crown)
 target_link_libraries(events crown)
+target_link_libraries(threads crown)
 
 add_test(allocators-test ${EXECUTABLE_OUTPUT_PATH}/allocators)
 add_test(containers-test ${EXECUTABLE_OUTPUT_PATH}/containers)
@@ -30,3 +32,4 @@ add_test(paths-test ${EXECUTABLE_OUTPUT_PATH}/paths)
 add_test(dynamic-string-test ${EXECUTABLE_OUTPUT_PATH}/dynamic-strings)
 add_test(json-test ${EXECUTABLE_OUTPUT_PATH}/json)
 add_test(events-test ${EXECUTABLE_OUTPUT_PATH}/events)
+add_test(threads-test ${EXECUTABLE_OUTPUT_PATH}/threads)

+ 31 - 0
engine/tests/threads.cpp

@@ -0,0 +1,31 @@
+#include "Thread.h"
+#include "Log.h"
+
+#include <unistd.h>
+
+using namespace crown;
+
+int32_t first_function(void* ft)
+{
+	OsThread* thread = (OsThread*)ft;
+
+	while(thread->is_running())
+	{
+		Log::i("I'm in the first thread");
+	}
+
+	return 0;
+}
+	
+int main()
+{
+	OsThread ft("first-thread");
+
+	ft.start(first_function, &ft);
+
+	sleep(2);
+
+	ft.stop();
+
+	return 0;
+}