Skip to content

Commit 171733b

Browse files
authored
Merge pull request swiftlang#585 from compnerd/overcommitted
event: support workqueue monitoring on Windows
2 parents ceabeea + 52f6e64 commit 171733b

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed

src/event/workqueue.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222

2323
#if DISPATCH_USE_INTERNAL_WORKQUEUE
2424

25+
#if defined(_WIN32)
26+
#include <wct.h>
27+
#endif
28+
2529
/*
2630
* dispatch_workq monitors the thread pool that is
2731
* executing the work enqueued on libdispatch's pthread
@@ -180,6 +184,64 @@ _dispatch_workq_count_runnable_workers(dispatch_workq_monitor_t mon)
180184

181185
_dispatch_unfair_lock_unlock(&mon->registered_tid_lock);
182186
}
187+
#elif defined(_WIN32)
188+
static void
189+
_dispatch_workq_init_wct(void *hWCTSession)
190+
{
191+
// TODO(compnerd) this should have an associated CloseThreadWaitChainSession
192+
*(HWCT **)hWCTSession = OpenThreadWaitChainSession(0, NULL);
193+
}
194+
195+
static void
196+
_dispatch_workq_count_runnable_workers(dispatch_workq_monitor_t mon)
197+
{
198+
static dispatch_once_t _wct_init_pred;
199+
static HWCT hWCTSession;
200+
static WAITCHAIN_NODE_INFO wait_chain[WCT_MAX_NODE_COUNT];
201+
202+
dispatch_once_f(&_wct_init_pred, &hWCTSession, &_dispatch_workq_init_wct);
203+
204+
int running_count = 0;
205+
206+
_dispatch_unfair_lock_lock(&mon->registered_tid_lock);
207+
208+
for (int i = 0; i < mon->num_registered_tids; ++i) {
209+
/* See _dispatch_tid_self() */
210+
dispatch_tid tid = mon->registered_tids[i] >> 2;
211+
212+
DWORD count = WCT_MAX_NODE_COUNT;
213+
BOOL cycle = FALSE;
214+
if (GetThreadWaitChain(hWCTSession, 0, 0, tid, &count, wait_chain, &cycle)) {
215+
// Check the deepest entry to see what the thread is waiting on.
216+
DWORD index = MIN(count, WCT_MAX_NODE_COUNT) - 1;
217+
if (wait_chain[index].ObjectType == WctThreadType) {
218+
if (wait_chain[index].ObjectStatus != WctStatusRunning) {
219+
continue;
220+
}
221+
}
222+
}
223+
224+
// Ensure that the thread is not waiting on IO
225+
// XXX(compnerd) is this needed? The wait chain reports SMB
226+
// and Socket IO, but it is unclear if that includes normal IO.
227+
HANDLE hThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, tid);
228+
if (hThread == NULL) {
229+
_dispatch_debug("workq: unable to open thread %u: %u", tid, GetLastError());
230+
continue;
231+
}
232+
233+
BOOL IOPending = TRUE;
234+
if (GetThreadIOPendingFlag(hThread, &IOPending))
235+
if (!IOPending)
236+
++running_count;
237+
238+
CloseHandle(hThread);
239+
}
240+
241+
mon->num_runnable = running_count;
242+
243+
_dispatch_unfair_lock_unlock(&mon->registered_tid_lock);
244+
}
183245
#else
184246
#error must define _dispatch_workq_count_runnable_workers
185247
#endif

src/event/workqueue_internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
void _dispatch_workq_worker_register(dispatch_queue_global_t root_q);
3131
void _dispatch_workq_worker_unregister(dispatch_queue_global_t root_q);
3232

33-
#if defined(__linux__)
33+
#if defined(__linux__) || defined(_WIN32)
3434
#define HAVE_DISPATCH_WORKQ_MONITORING 1
3535
#else
3636
#define HAVE_DISPATCH_WORKQ_MONITORING 0

0 commit comments

Comments
 (0)