Skip to content

Commit 7020636

Browse files
Handle spurious wakeups in Thread#join.
1 parent a4281f0 commit 7020636

File tree

2 files changed

+10
-7
lines changed

2 files changed

+10
-7
lines changed

scheduler.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,18 +146,18 @@ blocking_operation_call(VALUE self)
146146
rb_fiber_scheduler_blocking_operation_t *blocking_operation = get_blocking_operation(self);
147147

148148
if (blocking_operation->status != RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_QUEUED) {
149-
rb_raise(rb_eRuntimeError, "Blocking operation has already been executed");
149+
rb_raise(rb_eRuntimeError, "Blocking operation has already been executed!");
150150
}
151151

152152
if (blocking_operation->function == NULL) {
153-
rb_raise(rb_eRuntimeError, "Blocking operation has no function to execute");
153+
rb_raise(rb_eRuntimeError, "Blocking operation has no function to execute!");
154154
}
155155

156156
if (blocking_operation->state == NULL) {
157-
rb_raise(rb_eRuntimeError, "Blocking operation has no result object");
157+
rb_raise(rb_eRuntimeError, "Blocking operation has no result object!");
158158
}
159159

160-
// Mark as executing
160+
// Mark as executing
161161
blocking_operation->status = RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_EXECUTING;
162162

163163
// Execute the blocking operation without GVL
@@ -1076,7 +1076,7 @@ VALUE rb_fiber_scheduler_blocking_operation_wait(VALUE scheduler, void* (*functi
10761076

10771077
// If the blocking operation was never executed, return Qundef to signal
10781078
// the caller to use rb_nogvl instead
1079-
if (current_status == RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_QUEUED) {
1079+
if (current_status != RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_COMPLETED) {
10801080
return Qundef;
10811081
}
10821082

thread.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,8 +1060,10 @@ thread_join_sleep(VALUE arg)
10601060
rb_fiber_scheduler_block(scheduler, target_th->self, p->timeout);
10611061
// Check if the target thread is finished after blocking:
10621062
if (thread_finished(target_th)) break;
1063-
// Otherwise, a timeout occurred:
1064-
else return Qfalse;
1063+
// Otherwise, a timeout may have occurred:
1064+
else if (RTEST(p->timeout)) {
1065+
return Qfalse;
1066+
}
10651067
}
10661068
else if (!limit) {
10671069
sleep_forever(th, SLEEP_DEADLOCKABLE | SLEEP_ALLOW_SPURIOUS | SLEEP_NO_CHECKINTS);
@@ -1749,6 +1751,7 @@ io_blocking_operation_exit(VALUE _arguments)
17491751
rb_fiber_t *fiber = io->closing_ec->fiber_ptr;
17501752

17511753
if (thread->scheduler != Qnil) {
1754+
// This can cause spurious wakeups...
17521755
rb_fiber_scheduler_unblock(thread->scheduler, io->self, rb_fiberptr_self(fiber));
17531756
}
17541757
else {

0 commit comments

Comments
 (0)