|
23 | 23 | #include "protocol.h" // _dispatch_send_wakeup_runloop_thread |
24 | 24 | #endif |
25 | 25 |
|
| 26 | +#if defined(__linux__) |
| 27 | +#include <errno.h> |
| 28 | +#include <sys/resource.h> |
| 29 | +#endif |
| 30 | + |
| 31 | +#if defined(_WIN32) |
| 32 | +// Wrapper around SetThreadDescription for UTF-8 strings |
| 33 | +void _dispatch_win32_set_thread_description(HANDLE hThread, const char *description) { |
| 34 | + int wcsize = MultiByteToWideChar(CP_UTF8, 0, description, -1, NULL, 0); |
| 35 | + if (wcsize == 0) { |
| 36 | + return; |
| 37 | + } |
| 38 | + |
| 39 | + wchar_t* wcstr = (wchar_t*)malloc(wcsize * sizeof(wchar_t)); |
| 40 | + if (wcstr == NULL) { |
| 41 | + return; |
| 42 | + } |
| 43 | + |
| 44 | + int result = MultiByteToWideChar(CP_UTF8, 0, description, -1, wcstr, wcsize); |
| 45 | + if (result != 0) { |
| 46 | + SetThreadDescription(hThread, wcstr); |
| 47 | + } |
| 48 | + |
| 49 | + free(wcstr); |
| 50 | +} |
| 51 | +#endif |
| 52 | + |
26 | 53 | static inline void _dispatch_root_queues_init(void); |
27 | 54 | static void _dispatch_lane_barrier_complete(dispatch_lane_class_t dqu, |
28 | 55 | dispatch_qos_t qos, dispatch_wakeup_flags_t flags); |
@@ -6216,10 +6243,61 @@ _dispatch_worker_thread(void *context) |
6216 | 6243 | _dispatch_sigmask(); |
6217 | 6244 | #endif |
6218 | 6245 | _dispatch_introspection_thread_add(); |
| 6246 | + dispatch_priority_t pri = dq->dq_priority; |
| 6247 | + pthread_priority_t pp = _dispatch_get_priority(); |
| 6248 | + |
| 6249 | +#if defined(__linux__) |
| 6250 | + // The Linux kernel does not have a direct analogue to the QoS-based |
| 6251 | + // thread policy engine found in XNU. |
| 6252 | + // |
| 6253 | + // We cannot use 'pthread_setschedprio', because all threads with default |
| 6254 | + // scheduling policy (SCHED_OTHER) have the same pthread 'priority'. |
| 6255 | + // For both CFS, which was introduced in Linux 2.6.23, and its successor |
| 6256 | + // EEVDF (since 6.6) 'sched_get_priority_max' and 'sched_get_priority_min' |
| 6257 | + // will just return 0. |
| 6258 | + // |
| 6259 | + // However, as outlined in "man 2 setpriority", the nice value is a |
| 6260 | + // per‐thread attribute: different threads in the same process can have |
| 6261 | + // different nice values. We can thus setup the thread's initial priority |
| 6262 | + // by converting the QoS class and relative priority to a 'nice' value. |
| 6263 | + pp = _dispatch_priority_to_pp_strip_flags(pri); |
| 6264 | + int nice = _dispatch_pp_to_nice(pp); |
| 6265 | + |
| 6266 | + #if HAVE_PTHREAD_SETNAME_NP |
| 6267 | + // pthread thread names are restricted to just 16 characters |
| 6268 | + // including NUL. It does not make sense to pass the queue's |
| 6269 | + // label as a name. |
| 6270 | + pthread_setname_np(pthread_self(), "DispatchWorker"); |
| 6271 | + #endif |
| 6272 | + |
| 6273 | + errno = 0; |
| 6274 | + int rc = setpriority(PRIO_PROCESS, 0, nice); |
| 6275 | + if (rc != -1 || errno == 0) { |
| 6276 | + _dispatch_thread_setspecific(dispatch_priority_key, (void *)(uintptr_t)pp); |
| 6277 | + } else { |
| 6278 | + _dispatch_log("Failed to set thread priority for worker thread: pqc=%p errno=%d\n", pqc, errno); |
| 6279 | + } |
| 6280 | +#elif defined(_WIN32) |
| 6281 | + pp = _dispatch_priority_to_pp_strip_flags(pri); |
| 6282 | + int win_priority = _dispatch_pp_to_win32_priority(pp); |
| 6283 | + |
| 6284 | + HANDLE current = GetCurrentThread(); |
| 6285 | + |
| 6286 | + // Set thread description to the label of the root queue |
| 6287 | + if (dq->dq_label) { |
| 6288 | + _dispatch_win32_set_thread_description(current, dq->dq_label); |
| 6289 | + } |
| 6290 | + |
| 6291 | + int rc = SetThreadPriority(current, win_priority); |
| 6292 | + if (rc) { |
| 6293 | + _dispatch_thread_setspecific(dispatch_priority_key, (void *)(uintptr_t)pp); |
| 6294 | + } else { |
| 6295 | + DWORD dwError = GetLastError(); |
| 6296 | + _dispatch_log("Failed to set thread priority for worker thread: pqc=%p win_priority=%d dwError=%lu\n", pqc, win_priority, dwError); |
| 6297 | + } |
| 6298 | +#endif |
6219 | 6299 |
|
6220 | 6300 | const int64_t timeout = 5ull * NSEC_PER_SEC; |
6221 | | - pthread_priority_t pp = _dispatch_get_priority(); |
6222 | | - dispatch_priority_t pri = dq->dq_priority; |
6223 | 6301 |
|
6224 | 6302 | // If the queue is neither |
6225 | 6303 | // - the manager |
@@ -6258,6 +6336,14 @@ _dispatch_worker_thread(void *context) |
6258 | 6336 | (void)os_atomic_inc2o(dq, dgq_thread_pool_size, release); |
6259 | 6337 | _dispatch_root_queue_poke(dq, 1, 0); |
6260 | 6338 | _dispatch_release(dq); // retained in _dispatch_root_queue_poke_slow |
| 6339 | + |
| 6340 | +#if defined(_WIN32) |
| 6341 | + // Make sure to properly end the background processing mode |
| 6342 | + if (win_priority == THREAD_MODE_BACKGROUND_BEGIN) { |
| 6343 | + SetThreadPriority(current, THREAD_MODE_BACKGROUND_END); |
| 6344 | + } |
| 6345 | +#endif |
| 6346 | + |
6261 | 6347 | return NULL; |
6262 | 6348 | } |
6263 | 6349 | #if defined(_WIN32) |
|
0 commit comments