|
22 | 22 |
|
23 | 23 | #if DISPATCH_USE_INTERNAL_WORKQUEUE
|
24 | 24 |
|
| 25 | +#if defined(_WIN32) |
| 26 | +#include <wct.h> |
| 27 | +#endif |
| 28 | + |
25 | 29 | /*
|
26 | 30 | * dispatch_workq monitors the thread pool that is
|
27 | 31 | * executing the work enqueued on libdispatch's pthread
|
@@ -180,6 +184,64 @@ _dispatch_workq_count_runnable_workers(dispatch_workq_monitor_t mon)
|
180 | 184 |
|
181 | 185 | _dispatch_unfair_lock_unlock(&mon->registered_tid_lock);
|
182 | 186 | }
|
| 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 | +} |
183 | 245 | #else
|
184 | 246 | #error must define _dispatch_workq_count_runnable_workers
|
185 | 247 | #endif
|
|
0 commit comments