diff options
| author | Luke Gruber <luke.gruber@shopify.com> | 2025-11-10 20:32:30 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-11-10 20:32:30 -0500 |
| commit | d2c30a3bae908772c1de453aad8686000f6a5096 (patch) | |
| tree | 6fcaa68d47b5a9754724949f8cbf6ab714ab0f10 /thread_pthread.c | |
| parent | 222d8990d4b0acfd17db9bf9063af1ccf0fe036a (diff) | |
Fix `thread_sched_wait_events` race (#15067)
This race condition was found when calling `Thread#join` with a timeout
inside a ractor. The race is between the polling thread waking up the
thread and the `ubf` getting called (`ubf_event_waiting`). The error was
that the ubf or polling thread would set the thread as ready, but then
the other function would do the same.
Fixes [Bug #21614]
Diffstat (limited to 'thread_pthread.c')
| -rw-r--r-- | thread_pthread.c | 32 |
1 files changed, 18 insertions, 14 deletions
diff --git a/thread_pthread.c b/thread_pthread.c index 64912a58da..2eaa407f10 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -2592,16 +2592,14 @@ ubf_threads_empty(void) static void ubf_wakeup_all_threads(void) { - if (!ubf_threads_empty()) { - rb_thread_t *th; - rb_native_mutex_lock(&ubf_list_lock); - { - ccan_list_for_each(&ubf_list_head, th, sched.node.ubf) { - ubf_wakeup_thread(th); - } + rb_thread_t *th; + rb_native_mutex_lock(&ubf_list_lock); + { + ccan_list_for_each(&ubf_list_head, th, sched.node.ubf) { + ubf_wakeup_thread(th); } - rb_native_mutex_unlock(&ubf_list_lock); } + rb_native_mutex_unlock(&ubf_list_lock); } #else /* USE_UBF_LIST */ @@ -2996,6 +2994,17 @@ timer_thread_deq_wakeup(rb_vm_t *vm, rb_hrtime_t now) } static void +timer_thread_wakeup_thread_locked(struct rb_thread_sched *sched, rb_thread_t *th) +{ + if (sched->running != th) { + thread_sched_to_ready_common(sched, th, true, false); + } + else { + // will be release the execution right + } +} + +static void timer_thread_wakeup_thread(rb_thread_t *th) { RUBY_DEBUG_LOG("th:%u", rb_th_serial(th)); @@ -3003,12 +3012,7 @@ timer_thread_wakeup_thread(rb_thread_t *th) thread_sched_lock(sched, th); { - if (sched->running != th) { - thread_sched_to_ready_common(sched, th, true, false); - } - else { - // will be release the execution right - } + timer_thread_wakeup_thread_locked(sched, th); } thread_sched_unlock(sched, th); } |
