@@ -4,10 +4,14 @@ ThreadPool::ThreadPool(int numberOfThreads, uv_loop_t *loop) {
44 uv_mutex_init (&workMutex);
55 uv_sem_init (&workSemaphore, 0 );
66
7- uv_async_init (loop, &loopAsync, RunLoopCallbacks);
8- loopAsync.data = this ;
9- uv_unref ((uv_handle_t *)&loopAsync);
10- uv_mutex_init (&loopMutex);
7+ uv_async_init (loop, &completionAsync, RunCompletionCallbacks);
8+ completionAsync.data = this ;
9+ uv_unref ((uv_handle_t *)&completionAsync);
10+ uv_mutex_init (&completionMutex);
11+
12+ uv_async_init (loop, &reverseAsync, RunReverseCallbacks);
13+ reverseAsync.data = this ;
14+ uv_mutex_init (&reverseMutex);
1115
1216 workInProgressCount = 0 ;
1317
@@ -17,17 +21,31 @@ ThreadPool::ThreadPool(int numberOfThreads, uv_loop_t *loop) {
1721 }
1822}
1923
20- void ThreadPool::QueueWork (Callback workCallback, Callback loopCallback , void *data) {
24+ void ThreadPool::QueueWork (Callback workCallback, Callback completionCallback , void *data) {
2125 uv_mutex_lock (&workMutex);
2226 // there is work on the thread pool - reference the handle so
2327 // node doesn't terminate
24- uv_ref ((uv_handle_t *)&loopAsync );
25- workQueue.push (Work (workCallback, loopCallback , data));
28+ uv_ref ((uv_handle_t *)&completionAsync );
29+ workQueue.push (Work (workCallback, completionCallback , data));
2630 workInProgressCount++;
2731 uv_mutex_unlock (&workMutex);
2832 uv_sem_post (&workSemaphore);
2933}
3034
35+ void ThreadPool::ExecuteReverseCallback (Callback reverseCallback, void *data) {
36+ // push the callback into the queue
37+ uv_mutex_lock (&reverseMutex);
38+ ReverseCall reverseCall (reverseCallback, data);
39+ bool queueWasEmpty = reverseQueue.empty ();
40+ reverseQueue.push (reverseCall);
41+ // we only trigger RunReverseCallbacks via the reverseAsync handle if the queue
42+ // was empty. Otherwise, we depend on RunReverseCallbacks to re-trigger itself
43+ if (queueWasEmpty) {
44+ uv_async_send (&reverseAsync);
45+ }
46+ uv_mutex_unlock (&reverseMutex);
47+ }
48+
3149void ThreadPool::RunEventQueue (void *threadPool) {
3250 static_cast <ThreadPool *>(threadPool)->RunEventQueue ();
3351}
@@ -46,40 +64,62 @@ void ThreadPool::RunEventQueue() {
4664 (*work.workCallback )(work.data );
4765
4866 // schedule the callback on the loop
49- uv_mutex_lock (&loopMutex );
50- loopQueue .push (work);
51- uv_mutex_unlock (&loopMutex );
52- uv_async_send (&loopAsync );
67+ uv_mutex_lock (&completionMutex );
68+ completionQueue .push (work);
69+ uv_mutex_unlock (&completionMutex );
70+ uv_async_send (&completionAsync );
5371 }
5472}
5573
56- void ThreadPool::RunLoopCallbacks (uv_async_t * handle) {
57- static_cast <ThreadPool *>(handle->data )->RunLoopCallbacks ();
74+ void ThreadPool::RunCompletionCallbacks (uv_async_t * handle) {
75+ static_cast <ThreadPool *>(handle->data )->RunCompletionCallbacks ();
5876}
5977
60- void ThreadPool::RunLoopCallbacks () {
78+ void ThreadPool::RunCompletionCallbacks () {
6179 // uv_async_send can coalesce calls, so we are not guaranteed one
62- // RunLoopCallbacks per uv_async_send call
63- // so we always process the entire loopQueue
80+ // RunCompletionCallbacks per uv_async_send call
81+ // so we always process the entire completionQueue
6482 int callbacksCompleted = 0 ;
65- uv_mutex_lock (&loopMutex );
66- while (!loopQueue .empty ()) {
67- Work work = loopQueue .front ();
68- loopQueue .pop ();
69- uv_mutex_unlock (&loopMutex );
83+ uv_mutex_lock (&completionMutex );
84+ while (!completionQueue .empty ()) {
85+ Work work = completionQueue .front ();
86+ completionQueue .pop ();
87+ uv_mutex_unlock (&completionMutex );
7088 // perform the queued loop callback
71- (*work.loopCallback )(work.data );
89+ (*work.completionCallback )(work.data );
7290 callbacksCompleted++;
73- uv_mutex_lock (&loopMutex );
91+ uv_mutex_lock (&completionMutex );
7492 }
75- uv_mutex_unlock (&loopMutex );
93+ uv_mutex_unlock (&completionMutex );
7694
7795 uv_mutex_lock (&workMutex);
7896 // if there is no ongoing work / completion processing, node doesn't need
7997 // to be prevented from terminating
8098 workInProgressCount -= callbacksCompleted;
8199 if (!workInProgressCount) {
82- uv_unref ((uv_handle_t *)&loopAsync );
100+ uv_unref ((uv_handle_t *)&completionAsync );
83101 }
84102 uv_mutex_unlock (&workMutex);
85103}
104+
105+ void ThreadPool::RunReverseCallbacks (uv_async_t * handle) {
106+ static_cast <ThreadPool *>(handle->data )->RunReverseCallbacks ();
107+ }
108+
109+ void ThreadPool::RunReverseCallbacks () {
110+ // get the next callback to run
111+ uv_mutex_lock (&reverseMutex);
112+ ReverseCall reverseCall = reverseQueue.front ();
113+ uv_mutex_unlock (&reverseMutex);
114+
115+ // execute callback
116+ (*reverseCall.reverseCallback )(reverseCall.data );
117+
118+ // pop the queue, and if necessary, re-trigger RunReverseCallbacks
119+ uv_mutex_lock (&reverseMutex);
120+ reverseQueue.pop ();
121+ if (!reverseQueue.empty ()) {
122+ uv_async_send (&reverseAsync);
123+ }
124+ uv_mutex_unlock (&reverseMutex);
125+ }
0 commit comments