[PATCH v2 16/18] mt retrace: add workqueue support
Imre Deak
imre.deak at intel.com
Tue May 15 07:11:11 PDT 2012
Signed-off-by: Imre Deak <imre.deak at intel.com>
---
CMakeLists.txt | 3 +
common/os_workqueue.hpp | 49 ++++++++++++++++++
common/workqueue_posix.cpp | 116 ++++++++++++++++++++++++++++++++++++++++++++
common/workqueue_win32.cpp | 48 ++++++++++++++++++
4 files changed, 216 insertions(+), 0 deletions(-)
create mode 100644 common/os_workqueue.hpp
create mode 100644 common/workqueue_posix.cpp
create mode 100644 common/workqueue_win32.cpp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 37b2b27..5551cf7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -261,8 +261,10 @@ 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 ()
@@ -292,6 +294,7 @@ add_library (common STATIC
common/image_pnm.cpp
common/image_png.cpp
common/${os}
+ common/${workqueue}
)
set_target_properties (common PROPERTIES
diff --git a/common/os_workqueue.hpp b/common/os_workqueue.hpp
new file mode 100644
index 0000000..e6b77d4
--- /dev/null
+++ b/common/os_workqueue.hpp
@@ -0,0 +1,49 @@
+#ifndef _OS_WORKQUEUE_HPP_
+#define _OS_WORKQUEUE_HPP_
+
+#include <queue>
+
+namespace os
+{
+
+class WorkQueue;
+
+class WorkQueueWork {
+protected:
+ friend class WorkQueue;
+
+public:
+ virtual void run(void) = 0;
+ virtual ~WorkQueueWork(void) { }
+};
+
+extern "C"
+void *WorkQueue__entry_thunk(void *data);
+
+class WorkQueue {
+ pthread_t handle;
+ std::queue<WorkQueueWork *> work_queue;
+
+ bool busy;
+ bool exit_workqueue;
+ pthread_cond_t wake_cond;
+ pthread_cond_t complete_cond;
+
+ pthread_mutex_t lock;
+
+ void wake_up_thread(void);
+ void thread_entry(void);
+ int run_tasks(void);
+ friend void *WorkQueue__entry_thunk(void *data);
+public:
+ void queue_work(WorkQueueWork *work);
+ void flush(void);
+ void destroy(void);
+
+ WorkQueue(void);
+ ~WorkQueue();
+};
+
+}
+
+#endif
diff --git a/common/workqueue_posix.cpp b/common/workqueue_posix.cpp
new file mode 100644
index 0000000..8b36327
--- /dev/null
+++ b/common/workqueue_posix.cpp
@@ -0,0 +1,116 @@
+#include <pthread.h>
+#include <queue>
+#include <assert.h>
+
+#include "os_workqueue.hpp"
+
+namespace os
+{
+
+/**
+ * return 0 on batch complete, -1 on thread exit request.
+ */
+int WorkQueue::run_tasks(void)
+{
+ pthread_mutex_lock(&lock);
+
+ while (work_queue.empty() && !exit_workqueue)
+ pthread_cond_wait(&wake_cond, &lock);
+
+ if (exit_workqueue) {
+ pthread_mutex_unlock(&lock);
+ return -1;
+ }
+
+ std::queue<WorkQueueWork *> batch;
+ std::swap(work_queue, batch);
+ busy = true;
+
+ pthread_mutex_unlock(&lock);
+
+ assert(!batch.empty());
+ while (!batch.empty()) {
+ WorkQueueWork *task;
+
+ task = batch.front();
+ task->run();
+ batch.pop();
+ }
+
+ pthread_mutex_lock(&lock);
+
+ busy = false;
+ pthread_cond_signal(&complete_cond);
+
+ pthread_mutex_unlock(&lock);
+
+ return 0;
+}
+
+/* Must be called with WorkQueue::lock held */
+void WorkQueue::wake_up_thread(void)
+{
+ pthread_cond_signal(&wake_cond);
+}
+
+void WorkQueue::queue_work(WorkQueueWork *task)
+{
+ pthread_mutex_lock(&lock);
+ work_queue.push(task);
+ wake_up_thread();
+ pthread_mutex_unlock(&lock);
+}
+
+void WorkQueue::flush(void)
+{
+ pthread_mutex_lock(&lock);
+ while (!work_queue.empty() || busy)
+ pthread_cond_wait(&complete_cond, &lock);
+ pthread_mutex_unlock(&lock);
+}
+
+void WorkQueue::thread_entry(void)
+{
+ int err;
+
+ do {
+ err = run_tasks();
+ } while (!err);
+}
+
+void WorkQueue::destroy(void)
+{
+ pthread_mutex_lock(&lock);
+ exit_workqueue = true;
+ wake_up_thread();
+ pthread_mutex_unlock(&lock);
+}
+
+extern "C"
+void *WorkQueue__entry_thunk(void *data)
+{
+ WorkQueue *thread = static_cast<WorkQueue *>(data);
+
+ thread->thread_entry();
+
+ return NULL;
+}
+
+WorkQueue::WorkQueue(void) :
+ busy(false), exit_workqueue(false)
+{
+ int err;
+
+ pthread_cond_init(&wake_cond, NULL);
+ pthread_cond_init(&complete_cond, NULL);
+ pthread_mutex_init(&lock, NULL);
+ err = pthread_create(&handle, NULL, WorkQueue__entry_thunk, this);
+ assert(!err);
+}
+
+WorkQueue::~WorkQueue(void)
+{
+ pthread_join(handle, NULL);
+}
+
+}
diff --git a/common/workqueue_win32.cpp b/common/workqueue_win32.cpp
new file mode 100644
index 0000000..cec6693
--- /dev/null
+++ b/common/workqueue_win32.cpp
@@ -0,0 +1,48 @@
+#include <pthread.h>
+#include <queue>
+#include <assert.h>
+
+#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)
+{
+}
+
+}
--
1.7.5.4
More information about the apitrace
mailing list