/* * Copyright (c) 2012-2014 Daniele Bartolini and individual contributors. * License: https://github.com/taylor001/crown/blob/master/LICENSE */ #pragma once #include "config.h" #include "assert.h" #include "types.h" #include "semaphore.h" #if CROWN_PLATFORM_POSIX #include #elif CROWN_PLATFORM_WINDOWS #include "win_headers.h" #include #endif namespace crown { typedef int32_t (*ThreadFunction)(void*); struct Thread { Thread() #if CROWN_PLATFORM_POSIX : _handle(0) #elif CROWN_PLATFORM_WINDOWS : _handle(INVALID_HANDLE_VALUE) #endif , _function(NULL) , _data(NULL) , _stack_size(0) , _is_running(false) { } ~Thread() { if (_is_running) stop(); } void start(ThreadFunction func, void* data = NULL, size_t stack_size = 0) { CE_ASSERT(!_is_running, "Thread is already running"); CE_ASSERT(func != NULL, "Function must be != NULL"); _function = func; _data = data; _stack_size = stack_size; #if CROWN_PLATFORM_POSIX pthread_attr_t attr; int result = pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); CE_ASSERT(result == 0, "pthread_attr_init: errno = %d", result); if (_stack_size != 0) { result = pthread_attr_setstacksize(&attr, _stack_size); CE_ASSERT(result == 0, "pthread_attr_setstacksize: errno = %d", result); } result = pthread_create(&_handle, &attr, thread_proc, this); CE_ASSERT(result == 0, "pthread_create: errno = %d", result); // Free attr memory result = pthread_attr_destroy(&attr); CE_ASSERT(result == 0, "pthread_attr_destroy: errno = %d", result); CE_UNUSED(result); #elif CROWN_PLATFORM_WINDOWS _handle = CreateThread(NULL, stack_size, Thread::thread_proc, this, 0, NULL); CE_ASSERT(_handle != NULL, "CreateThread: GetLastError = %d", GetLastError()); #endif _is_running = true; _sem.wait(); } void stop() { CE_ASSERT(_is_running, "Thread is not running"); #if CROWN_PLATFORM_POSIX int result = pthread_join(_handle, NULL); CE_ASSERT(result == 0, "pthread_join: errno = %d", result); CE_UNUSED(result); _handle = 0; #elif CROWN_PLATFORM_WINDOWS WaitForSingleObject(_handle, INFINITE); // GetExitCodeThread(_handle, &m_exit_code); CloseHandle(_handle); _handle = INVALID_HANDLE_VALUE; #endif _is_running = false; } bool is_running() { return _is_running; } private: int32_t run() { _sem.post(); return _function(_data); } #if CROWN_PLATFORM_POSIX static void* thread_proc(void* arg) { static int32_t result = -1; result = ((Thread*)arg)->run(); return (void*)&result; } #elif CROWN_PLATFORM_WINDOWS static DWORD WINAPI thread_proc(void* arg) { Thread* thread = (Thread*) arg; int32_t result = thread->run(); return result; } #endif private: #if CROWN_PLATFORM_POSIX pthread_t _handle; #elif CROWN_PLATFORM_WINDOWS HANDLE _handle; #endif ThreadFunction _function; void* _data; Semaphore _sem; size_t _stack_size; bool _is_running; private: // Disable copying Thread(const Thread&); Thread& operator=(const Thread&); }; } // namespace crown