To avoid deadlock with uv_cancel() it's crucial that the worker * never holds the global mutex and the loop-local mutex at the same time. */
| 55 | * never holds the global mutex and the loop-local mutex at the same time. |
| 56 | */ |
| 57 | static void worker(void* arg) { |
| 58 | struct uv__work* w; |
| 59 | struct uv__queue* q; |
| 60 | int is_slow_work; |
| 61 | |
| 62 | uv_sem_post((uv_sem_t*) arg); |
| 63 | arg = NULL; |
| 64 | |
| 65 | uv_mutex_lock(&mutex); |
| 66 | for (;;) { |
| 67 | /* `mutex` should always be locked at this point. */ |
| 68 | |
| 69 | /* Keep waiting while either no work is present or only slow I/O |
| 70 | and we're at the threshold for that. */ |
| 71 | while (uv__queue_empty(&wq) || |
| 72 | (uv__queue_head(&wq) == &run_slow_work_message && |
| 73 | uv__queue_next(&run_slow_work_message) == &wq && |
| 74 | slow_io_work_running >= slow_work_thread_threshold())) { |
| 75 | idle_threads += 1; |
| 76 | uv_cond_wait(&cond, &mutex); |
| 77 | idle_threads -= 1; |
| 78 | } |
| 79 | |
| 80 | q = uv__queue_head(&wq); |
| 81 | if (q == &exit_message) { |
| 82 | uv_cond_signal(&cond); |
| 83 | uv_mutex_unlock(&mutex); |
| 84 | break; |
| 85 | } |
| 86 | |
| 87 | uv__queue_remove(q); |
| 88 | uv__queue_init(q); /* Signal uv_cancel() that the work req is executing. */ |
| 89 | |
| 90 | is_slow_work = 0; |
| 91 | if (q == &run_slow_work_message) { |
| 92 | /* If we're at the slow I/O threshold, re-schedule until after all |
| 93 | other work in the queue is done. */ |
| 94 | if (slow_io_work_running >= slow_work_thread_threshold()) { |
| 95 | uv__queue_insert_tail(&wq, q); |
| 96 | continue; |
| 97 | } |
| 98 | |
| 99 | /* If we encountered a request to run slow I/O work but there is none |
| 100 | to run, that means it's cancelled => Start over. */ |
| 101 | if (uv__queue_empty(&slow_io_pending_wq)) |
| 102 | continue; |
| 103 | |
| 104 | is_slow_work = 1; |
| 105 | slow_io_work_running++; |
| 106 | |
| 107 | q = uv__queue_head(&slow_io_pending_wq); |
| 108 | uv__queue_remove(q); |
| 109 | uv__queue_init(q); |
| 110 | |
| 111 | /* If there is more slow I/O work, schedule it to be run as well. */ |
| 112 | if (!uv__queue_empty(&slow_io_pending_wq)) { |
| 113 | uv__queue_insert_tail(&wq, &run_slow_work_message); |
| 114 | if (idle_threads > 0) |
nothing calls this directly
no test coverage detected