@@ -127,6 +127,7 @@ void jl_threadfun(void *arg)
127
127
void jl_init_thread_scheduler (jl_ptls_t ptls ) JL_NOTSAFEPOINT
128
128
{
129
129
uv_mutex_init (& ptls -> sleep_lock );
130
+ ptls -> wake_all = 0 ;
130
131
uv_cond_init (& ptls -> wake_signal );
131
132
// record that there is now another thread that may be used to schedule work
132
133
// we will decrement this again in scheduler_delete_thread, only slightly
@@ -213,7 +214,7 @@ static int set_not_sleeping(jl_ptls_t ptls) JL_NOTSAFEPOINT
213
214
return 0 ;
214
215
}
215
216
216
- static int wake_thread (int16_t tid ) JL_NOTSAFEPOINT
217
+ static int wake_thread (int16_t tid , int wake_all ) JL_NOTSAFEPOINT
217
218
{
218
219
jl_ptls_t ptls2 = jl_atomic_load_relaxed (& jl_all_tls_states )[tid ];
219
220
@@ -224,6 +225,7 @@ static int wake_thread(int16_t tid) JL_NOTSAFEPOINT
224
225
assert (wasrunning ); (void )wasrunning ;
225
226
JL_PROBE_RT_SLEEP_CHECK_WAKE (ptls2 , state );
226
227
uv_mutex_lock (& ptls2 -> sleep_lock );
228
+ ptls2 -> wake_all = 1 ;
227
229
uv_cond_signal (& ptls2 -> wake_signal );
228
230
uv_mutex_unlock (& ptls2 -> sleep_lock );
229
231
return 1 ;
@@ -240,6 +242,21 @@ static void wake_libuv(void) JL_NOTSAFEPOINT
240
242
JULIA_DEBUG_SLEEPWAKE ( io_wakeup_leave = cycleclock () );
241
243
}
242
244
245
+ int wake_child_threads (int16_t self ) JL_NOTSAFEPOINT
246
+ {
247
+ int any_asleep = 0 ;
248
+ int nthreads = jl_atomic_load_acquire (& jl_n_threads );
249
+ int16_t tid1 = (2 * self ) + 1 ;
250
+ if (tid1 < nthreads ) {
251
+ any_asleep |= wake_thread (tid1 , 1 );
252
+ }
253
+ int16_t tid2 = (2 * self ) + 2 ;
254
+ if (tid2 < nthreads ) {
255
+ any_asleep |= wake_thread (tid2 , 1 );
256
+ }
257
+ return any_asleep ;
258
+ }
259
+
243
260
void wakeup_thread (jl_task_t * ct , int16_t tid ) JL_NOTSAFEPOINT { // Pass in ptls when we have it already available to save a lookup
244
261
int16_t self = jl_atomic_load_relaxed (& ct -> tid );
245
262
if (tid != self )
@@ -262,7 +279,7 @@ void wakeup_thread(jl_task_t *ct, int16_t tid) JL_NOTSAFEPOINT { // Pass in ptls
262
279
}
263
280
else {
264
281
// something added to the sticky-queue: notify that thread
265
- if (wake_thread (tid ) && uvlock != ct ) {
282
+ if (wake_thread (tid , 0 ) && uvlock != ct ) {
266
283
// check if we need to notify uv_run too
267
284
jl_fence ();
268
285
jl_ptls_t other = jl_atomic_load_relaxed (& jl_all_tls_states )[tid ];
@@ -279,14 +296,10 @@ void wakeup_thread(jl_task_t *ct, int16_t tid) JL_NOTSAFEPOINT { // Pass in ptls
279
296
// something added to the multi-queue: notify all threads
280
297
// in the future, we might want to instead wake some fraction of threads,
281
298
// and let each of those wake additional threads if they find work
282
- int anysleep = 0 ;
283
- int nthreads = jl_atomic_load_acquire (& jl_n_threads );
284
- for (tid = 0 ; tid < nthreads ; tid ++ ) {
285
- if (tid != self )
286
- anysleep |= wake_thread (tid );
287
- }
299
+ wake_child_threads (self );
300
+
288
301
// check if we need to notify uv_run too
289
- if (uvlock != ct && anysleep ) {
302
+ if (uvlock != ct ) {
290
303
jl_fence ();
291
304
if (jl_atomic_load_relaxed (& jl_uv_mutex .owner ) != NULL )
292
305
wake_libuv ();
@@ -518,6 +531,11 @@ JL_DLLEXPORT jl_task_t *jl_task_get_next(jl_value_t *trypoptask, jl_value_t *q,
518
531
}
519
532
// else should we warn the user of certain deadlock here if tid == 0 && n_threads_running == 0?
520
533
uv_cond_wait (& ptls -> wake_signal , & ptls -> sleep_lock );
534
+ // we were woken up; should we wake others?
535
+ if (!may_sleep (ptls ) && ptls -> wake_all ) {
536
+ ptls -> wake_all = 0 ;
537
+ wake_child_threads (ptls -> tid );
538
+ }
521
539
}
522
540
assert (jl_atomic_load_relaxed (& ptls -> sleep_check_state ) == not_sleeping );
523
541
assert (jl_atomic_load_relaxed (& n_threads_running ));
0 commit comments