summaryrefslogtreecommitdiff
path: root/thread_pthread.c
diff options
context:
space:
mode:
authorLuke Gruber <luke.gruber@shopify.com>2025-11-10 20:32:30 -0500
committerGitHub <noreply@github.com>2025-11-10 20:32:30 -0500
commitd2c30a3bae908772c1de453aad8686000f6a5096 (patch)
tree6fcaa68d47b5a9754724949f8cbf6ab714ab0f10 /thread_pthread.c
parent222d8990d4b0acfd17db9bf9063af1ccf0fe036a (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.c32
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);
}