@@ -127,6 +127,7 @@ void jl_threadfun(void *arg)
127127void jl_init_thread_scheduler (jl_ptls_t ptls ) JL_NOTSAFEPOINT
128128{
129129 uv_mutex_init (& ptls -> sleep_lock );
130+ ptls -> wake_all = 0 ;
130131 uv_cond_init (& ptls -> wake_signal );
131132 // record that there is now another thread that may be used to schedule work
132133 // 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
213214 return 0 ;
214215}
215216
216- static int wake_thread (int16_t tid ) JL_NOTSAFEPOINT
217+ static int wake_thread (int16_t tid , int wake_all ) JL_NOTSAFEPOINT
217218{
218219 jl_ptls_t ptls2 = jl_atomic_load_relaxed (& jl_all_tls_states )[tid ];
219220
@@ -224,6 +225,7 @@ static int wake_thread(int16_t tid) JL_NOTSAFEPOINT
224225 assert (wasrunning ); (void )wasrunning ;
225226 JL_PROBE_RT_SLEEP_CHECK_WAKE (ptls2 , state );
226227 uv_mutex_lock (& ptls2 -> sleep_lock );
228+ ptls2 -> wake_all = 1 ;
227229 uv_cond_signal (& ptls2 -> wake_signal );
228230 uv_mutex_unlock (& ptls2 -> sleep_lock );
229231 return 1 ;
@@ -240,6 +242,21 @@ static void wake_libuv(void) JL_NOTSAFEPOINT
240242 JULIA_DEBUG_SLEEPWAKE ( io_wakeup_leave = cycleclock () );
241243}
242244
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+
243260void wakeup_thread (jl_task_t * ct , int16_t tid ) JL_NOTSAFEPOINT { // Pass in ptls when we have it already available to save a lookup
244261 int16_t self = jl_atomic_load_relaxed (& ct -> tid );
245262 if (tid != self )
@@ -262,7 +279,7 @@ void wakeup_thread(jl_task_t *ct, int16_t tid) JL_NOTSAFEPOINT { // Pass in ptls
262279 }
263280 else {
264281 // something added to the sticky-queue: notify that thread
265- if (wake_thread (tid ) && uvlock != ct ) {
282+ if (wake_thread (tid , 0 ) && uvlock != ct ) {
266283 // check if we need to notify uv_run too
267284 jl_fence ();
268285 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
279296 // something added to the multi-queue: notify all threads
280297 // in the future, we might want to instead wake some fraction of threads,
281298 // 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+
288301 // check if we need to notify uv_run too
289- if (uvlock != ct && anysleep ) {
302+ if (uvlock != ct ) {
290303 jl_fence ();
291304 if (jl_atomic_load_relaxed (& jl_uv_mutex .owner ) != NULL )
292305 wake_libuv ();
@@ -518,6 +531,11 @@ JL_DLLEXPORT jl_task_t *jl_task_get_next(jl_value_t *trypoptask, jl_value_t *q,
518531 }
519532 // else should we warn the user of certain deadlock here if tid == 0 && n_threads_running == 0?
520533 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+ }
521539 }
522540 assert (jl_atomic_load_relaxed (& ptls -> sleep_check_state ) == not_sleeping );
523541 assert (jl_atomic_load_relaxed (& n_threads_running ));
0 commit comments