]> git.cworth.org Git - apitrace/blob - common/workqueue_posix.cpp
mt retrace: add workqueue support
[apitrace] / common / workqueue_posix.cpp
1 #include <pthread.h>
2 #include <queue>
3 #include <assert.h>
4
5 #include "os_workqueue.hpp"
6
7 namespace os
8 {
9
10 /**
11  * return 0 on batch complete, -1 on thread exit request.
12  */
13 int WorkQueue::run_tasks(void)
14 {
15     pthread_mutex_lock(&lock);
16
17     while (work_queue.empty() && !exit_workqueue)
18         pthread_cond_wait(&wake_cond, &lock);
19
20     if (exit_workqueue) {
21         pthread_mutex_unlock(&lock);
22         return -1;
23     }
24
25     std::queue<WorkQueueWork *> batch;
26     std::swap(work_queue, batch);
27     busy = true;
28
29     pthread_mutex_unlock(&lock);
30
31     assert(!batch.empty());
32     while (!batch.empty()) {
33         WorkQueueWork *task;
34
35         task = batch.front();
36         task->run();
37         batch.pop();
38         delete task;
39     }
40
41     pthread_mutex_lock(&lock);
42
43     busy = false;
44     pthread_cond_signal(&complete_cond);
45
46     pthread_mutex_unlock(&lock);
47
48     return 0;
49 }
50
51 /* Must be called with WorkQueue::lock held */
52 void WorkQueue::wake_up_thread(void)
53 {
54     pthread_cond_signal(&wake_cond);
55 }
56
57 void WorkQueue::queue_work(WorkQueueWork *task)
58 {
59     pthread_mutex_lock(&lock);
60     work_queue.push(task);
61     wake_up_thread();
62     pthread_mutex_unlock(&lock);
63 }
64
65 void WorkQueue::flush(void)
66 {
67     pthread_mutex_lock(&lock);
68     while (!work_queue.empty() || busy)
69         pthread_cond_wait(&complete_cond, &lock);
70     pthread_mutex_unlock(&lock);
71 }
72
73 void WorkQueue::thread_entry(void)
74 {
75     int err;
76
77     do {
78         err = run_tasks();
79     } while (!err);
80 }
81
82 void WorkQueue::destroy(void)
83 {
84     pthread_mutex_lock(&lock);
85     exit_workqueue = true;
86     wake_up_thread();
87     pthread_mutex_unlock(&lock);
88 }
89
90 extern "C"
91 void *WorkQueue__entry_thunk(void *data)
92 {
93     WorkQueue *thread = static_cast<WorkQueue *>(data);
94
95     thread->thread_entry();
96
97     return NULL;
98 }
99
100 WorkQueue::WorkQueue(void) :
101     busy(false), exit_workqueue(false)
102 {
103     int err;
104
105     pthread_cond_init(&wake_cond, NULL);
106     pthread_cond_init(&complete_cond, NULL);
107     pthread_mutex_init(&lock, NULL);
108     err = pthread_create(&handle, NULL, WorkQueue__entry_thunk, this);
109     assert(!err);
110 }
111
112 WorkQueue::~WorkQueue(void)
113 {
114     pthread_join(handle, NULL);
115 }
116
117 }