From: José Fonseca Date: Tue, 23 Oct 2012 19:15:36 +0000 (+0100) Subject: Implement missing threading primitive for Windows. X-Git-Url: https://git.cworth.org/git?p=apitrace;a=commitdiff_plain;h=743d6c75f3edfb728f689027347d2de9b0068425 Implement missing threading primitive for Windows. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index a4f01fb..6329689 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,10 +272,8 @@ include_directories ( if (WIN32) set (os os_win32.cpp) set (glws_os glws_wgl.cpp) - set (workqueue workqueue_win32.cpp) else () set (os os_posix.cpp) - set (workqueue workqueue_posix.cpp) if (APPLE) set (glws_os glws_cocoa.mm) else () @@ -306,7 +304,7 @@ add_library (common STATIC common/image_pnm.cpp common/image_png.cpp common/${os} - common/${workqueue} + common/workqueue.cpp ) set_target_properties (common PROPERTIES diff --git a/common/os_thread.hpp b/common/os_thread.hpp index 9d6a989..72195b6 100644 --- a/common/os_thread.hpp +++ b/common/os_thread.hpp @@ -187,14 +187,14 @@ namespace os { { public: #ifdef _WIN32 - /* FIXME */ + typedef CONDITION_VARIABLE native_handle_type; #else typedef pthread_cond_t native_handle_type; #endif condition_variable() { #ifdef _WIN32 - /* FIXME */ + InitializeConditionVariable(&_native_handle); #else pthread_cond_init(&_native_handle, NULL); #endif @@ -202,7 +202,7 @@ namespace os { ~condition_variable() { #ifdef _WIN32 - /* FIXME */ + /* No-op */ #else pthread_cond_destroy(&_native_handle); #endif @@ -211,7 +211,7 @@ namespace os { inline void signal(void) { #ifdef _WIN32 - /* FIXME */ + WakeConditionVariable(&_native_handle); #else pthread_cond_signal(&_native_handle); #endif @@ -219,10 +219,12 @@ namespace os { inline void wait(unique_lock & lock) { + mutex::native_handle_type & mutex_native_handle = lock.mutex()->native_handle(); #ifdef _WIN32 /* FIXME */ + SleepConditionVariableCS(&_native_handle, &mutex_native_handle, INFINITE); #else - pthread_cond_wait(&_native_handle, &lock.mutex()->native_handle()); + pthread_cond_wait(&_native_handle, &mutex_native_handle); #endif } @@ -305,7 +307,7 @@ namespace os { class thread { public: #ifdef _WIN32 - /* FIXME */ + typedef HANDLE native_handle_type; #else typedef pthread_t native_handle_type; #endif @@ -314,6 +316,8 @@ namespace os { explicit thread( Function& f, Arg & arg ) { #ifdef _WIN32 /* FIXME */ + DWORD id = 0; + _native_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)f, (LPVOID)arg, 0, &id); #else pthread_create(&_native_handle, NULL, f, arg); #endif @@ -322,7 +326,7 @@ namespace os { inline void join() { #ifdef _WIN32 - /* FIXME */ + WaitForSingleObject(_native_handle, INFINITE); #else pthread_join(_native_handle, NULL); #endif @@ -330,6 +334,16 @@ namespace os { private: native_handle_type _native_handle; + +#if 0 +#ifdef _WIN32 + template< class Function, class Arg > + static DWORD WINAPI + ThreadProc(LPVOID lpParameter) { + + ); +#endif +#endif }; } /* namespace os */ diff --git a/common/os_workqueue.hpp b/common/os_workqueue.hpp index f8ab84c..047d3db 100644 --- a/common/os_workqueue.hpp +++ b/common/os_workqueue.hpp @@ -19,9 +19,6 @@ public: virtual ~WorkQueueWork(void) { } }; -extern "C" -void *WorkQueue__entry_thunk(void *data); - class WorkQueue { std::queue work_queue; @@ -35,10 +32,9 @@ class WorkQueue { os::thread thread; void wake_up_thread(void); - void thread_entry(void); int run_tasks(void); - friend void *WorkQueue__entry_thunk(void *data); public: + void thread_entry(void); void queue_work(WorkQueueWork *work); void flush(void); void destroy(void); diff --git a/common/workqueue.cpp b/common/workqueue.cpp new file mode 100644 index 0000000..fcd697a --- /dev/null +++ b/common/workqueue.cpp @@ -0,0 +1,118 @@ +#include +#include + +#include "os_workqueue.hpp" + +namespace os +{ + +/** + * return 0 on batch complete, -1 on thread exit request. + */ +int WorkQueue::run_tasks(void) +{ + os::unique_lock lock(mutex); + + while (work_queue.empty() && !exit_workqueue) { + wake_cond.wait(lock); + } + + if (exit_workqueue) { + return -1; + } + + std::queue batch; + std::swap(work_queue, batch); + busy = true; + + lock.unlock(); + + assert(!batch.empty()); + while (!batch.empty()) { + WorkQueueWork *task; + + task = batch.front(); + task->run(); + batch.pop(); + delete task; + } + + lock.lock(); + + busy = false; + complete_cond.signal(); + + return 0; +} + +/* Must be called with WorkQueue::lock held */ +void WorkQueue::wake_up_thread(void) +{ + wake_cond.signal(); +} + +void WorkQueue::queue_work(WorkQueueWork *task) +{ + mutex.lock(); + work_queue.push(task); + wake_up_thread(); + mutex.unlock(); +} + +void WorkQueue::flush(void) +{ + os::unique_lock lock(mutex); + while (!work_queue.empty() || busy) { + complete_cond.wait(lock); + } +} + +void WorkQueue::thread_entry(void) +{ + int err; + + do { + err = run_tasks(); + } while (!err); +} + +void WorkQueue::destroy(void) +{ + mutex.lock(); + exit_workqueue = true; + wake_up_thread(); + mutex.unlock(); +} + +static +#ifdef _WIN32 +DWORD WINAPI +#else +void * +#endif +WorkQueue__entry_thunk(void *data) +{ + WorkQueue *thread = static_cast(data); + + thread->thread_entry(); + +#ifdef _WIN32 + return 0; +#else + return NULL; +#endif +} + +WorkQueue::WorkQueue(void) : + busy(false), + exit_workqueue(false), + thread(WorkQueue__entry_thunk, this) +{ +} + +WorkQueue::~WorkQueue(void) +{ + thread.join(); +} + +} diff --git a/common/workqueue_posix.cpp b/common/workqueue_posix.cpp deleted file mode 100644 index 7df7e54..0000000 --- a/common/workqueue_posix.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include -#include - -#include "os_workqueue.hpp" - -namespace os -{ - -/** - * return 0 on batch complete, -1 on thread exit request. - */ -int WorkQueue::run_tasks(void) -{ - os::unique_lock lock(mutex); - - while (work_queue.empty() && !exit_workqueue) { - wake_cond.wait(lock); - } - - if (exit_workqueue) { - return -1; - } - - std::queue batch; - std::swap(work_queue, batch); - busy = true; - - lock.unlock(); - - assert(!batch.empty()); - while (!batch.empty()) { - WorkQueueWork *task; - - task = batch.front(); - task->run(); - batch.pop(); - delete task; - } - - lock.lock(); - - busy = false; - complete_cond.signal(); - - return 0; -} - -/* Must be called with WorkQueue::lock held */ -void WorkQueue::wake_up_thread(void) -{ - wake_cond.signal(); -} - -void WorkQueue::queue_work(WorkQueueWork *task) -{ - mutex.lock(); - work_queue.push(task); - wake_up_thread(); - mutex.unlock(); -} - -void WorkQueue::flush(void) -{ - os::unique_lock lock(mutex); - while (!work_queue.empty() || busy) { - complete_cond.wait(lock); - } -} - -void WorkQueue::thread_entry(void) -{ - int err; - - do { - err = run_tasks(); - } while (!err); -} - -void WorkQueue::destroy(void) -{ - mutex.lock(); - exit_workqueue = true; - wake_up_thread(); - mutex.unlock(); -} - -void *WorkQueue__entry_thunk(void *data) -{ - WorkQueue *thread = static_cast(data); - - thread->thread_entry(); - - return NULL; -} - -WorkQueue::WorkQueue(void) : - busy(false), - exit_workqueue(false), - thread(WorkQueue__entry_thunk, this) -{ -} - -WorkQueue::~WorkQueue(void) -{ - thread.join(); -} - -} diff --git a/common/workqueue_win32.cpp b/common/workqueue_win32.cpp deleted file mode 100644 index 3c1b9cd..0000000 --- a/common/workqueue_win32.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include - -#include "os.hpp" -#include "os_workqueue.hpp" - -namespace os -{ - -/** - * return 0 on batch complete, -1 on thread exit request. - */ -int WorkQueue::run_tasks(void) -{ - return 0; -} - -void WorkQueue::queue_work(WorkQueueWork *task) -{ - task->run(); -} - -void WorkQueue::flush(void) -{ -} - -void WorkQueue::destroy(void) -{ -} - -WorkQueue::WorkQueue(void) : - busy(false), exit_workqueue(false) -{ - static bool warned; - - if (!warned) { - warned = true; - os::log("%s: no workqueue implementation, running in single-threaded mode\n", - __func__); - } -} - -WorkQueue::~WorkQueue(void) -{ -} - -}