Skip to content

Commit 62fa992

Browse files
committed
Disallow pending interrupts to be checked during FiberScheduler#unblock
Ractors can send signals at any time, so the previous debug assertion can fail if a Ractor sends a signal. ```ruby require 'async/scheduler' scheduler = Async::Scheduler.new Fiber.set_scheduler(scheduler) Signal.trap(:INT) do end q = Thread::Queue.new Thread.new do loop do Ractor.new do Process.kill(:INT, $$) end.value end end Fiber.schedule do Fiber.schedule do 1.upto(1000000) do |i| sleep 0.01 q.pop q.push(1) puts "1 iter push/pop" end end Fiber.schedule do 1.upto(1000000) do |i| sleep 0.01 q.push(i) q.pop puts "1 iter push/pop#2" end end end ```
1 parent 7dd9c76 commit 62fa992

File tree

2 files changed

+35
-11
lines changed

2 files changed

+35
-11
lines changed

depend

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15019,6 +15019,7 @@ scheduler.$(OBJEXT): {$(VPATH)}config.h
1501915019
scheduler.$(OBJEXT): {$(VPATH)}constant.h
1502015020
scheduler.$(OBJEXT): {$(VPATH)}defines.h
1502115021
scheduler.$(OBJEXT): {$(VPATH)}encoding.h
15022+
scheduler.$(OBJEXT): {$(VPATH)}eval_intern.h
1502215023
scheduler.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
1502315024
scheduler.$(OBJEXT): {$(VPATH)}id.h
1502415025
scheduler.$(OBJEXT): {$(VPATH)}id_table.h

scheduler.c

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
**********************************************************************/
1010

1111
#include "vm_core.h"
12+
#include "eval_intern.h"
1213
#include "ruby/fiber/scheduler.h"
1314
#include "ruby/io.h"
1415
#include "ruby/io/buffer.h"
@@ -647,18 +648,29 @@ rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber)
647648
{
648649
RUBY_ASSERT(rb_obj_is_fiber(fiber));
649650

651+
VALUE result;
652+
enum ruby_tag_type state;
650653
// `rb_fiber_scheduler_unblock` can be called from points where `errno` is expected to be preserved. Therefore, we should save and restore it. For example `io_binwrite` calls `rb_fiber_scheduler_unblock` and if `errno` is reset to 0 by user code, it will break the error handling in `io_write`.
651654
// If we explicitly preserve `errno` in `io_binwrite` and other similar functions (e.g. by returning it), this code is no longer needed. I hope in the future we will be able to remove it.
652655
int saved_errno = errno;
653656

654-
#ifdef RUBY_DEBUG
655657
rb_execution_context_t *ec = GET_EC();
656-
if (RUBY_VM_INTERRUPTED(ec)) {
657-
rb_bug("rb_fiber_scheduler_unblock called with pending interrupt");
658+
int old_interrupt_mask = ec->interrupt_mask;
659+
ec->interrupt_mask |= PENDING_INTERRUPT_MASK;
660+
661+
EC_PUSH_TAG(ec);
662+
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
663+
result = rb_funcall(scheduler, id_unblock, 2, blocker, fiber);
658664
}
659-
#endif
665+
EC_POP_TAG();
660666

661-
VALUE result = rb_funcall(scheduler, id_unblock, 2, blocker, fiber);
667+
ec->interrupt_mask = old_interrupt_mask;
668+
669+
if (state) {
670+
EC_JUMP_TAG(ec, state);
671+
}
672+
673+
RUBY_VM_CHECK_INTS();
662674

663675
errno = saved_errno;
664676

@@ -1079,15 +1091,26 @@ VALUE rb_fiber_scheduler_fiber_interrupt(VALUE scheduler, VALUE fiber, VALUE exc
10791091
VALUE arguments[] = {
10801092
fiber, exception
10811093
};
1082-
1083-
#ifdef RUBY_DEBUG
1094+
VALUE result;
1095+
enum ruby_tag_type state;
10841096
rb_execution_context_t *ec = GET_EC();
1085-
if (RUBY_VM_INTERRUPTED(ec)) {
1086-
rb_bug("rb_fiber_scheduler_fiber_interrupt called with pending interrupt");
1097+
int old_interrupt_mask = ec->interrupt_mask;
1098+
ec->interrupt_mask |= PENDING_INTERRUPT_MASK;
1099+
1100+
EC_PUSH_TAG(ec);
1101+
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1102+
result = rb_check_funcall(scheduler, id_fiber_interrupt, 2, arguments);
10871103
}
1088-
#endif
1104+
EC_POP_TAG();
1105+
1106+
ec->interrupt_mask = old_interrupt_mask;
10891107

1090-
return rb_check_funcall(scheduler, id_fiber_interrupt, 2, arguments);
1108+
if (state) {
1109+
EC_JUMP_TAG(ec, state);
1110+
}
1111+
1112+
RUBY_VM_CHECK_INTS();
1113+
return result;
10911114
}
10921115

10931116
/*

0 commit comments

Comments
 (0)