Introduce `Fiber.blocking{}` for bypassing the fiber scheduler. (#6498)

This commit is contained in:
Samuel Williams 2022-10-06 23:00:49 +13:00 коммит произвёл GitHub
Родитель 75a53f6be0
Коммит e696ec67ac
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 60 добавлений и 0 удалений

32
cont.c
Просмотреть файл

@ -2413,6 +2413,37 @@ rb_fiber_blocking_p(VALUE fiber)
return RBOOL(fiber_ptr(fiber)->blocking != 0);
}
static VALUE
fiber_blocking_yield(VALUE fiber)
{
fiber_ptr(fiber)->blocking += 1;
return rb_yield(fiber);
}
static VALUE
fiber_blocking_ensure(VALUE fiber)
{
fiber_ptr(fiber)->blocking -= 1;
return Qnil;
}
/*
* call-seq:
* Fiber.blocking{|fiber| ...} -> result
*
* Forces the fiber to be blocking for the duration of the block. Returns the
* result of the block.
*
* See the "Non-blocking fibers" section in class docs for details.
*
*/
VALUE
rb_fiber_blocking(VALUE class)
{
VALUE fiber = rb_fiber_current();
return rb_ensure(fiber_blocking_yield, fiber, fiber_blocking_ensure, fiber);
}
/*
* call-seq:
* Fiber.blocking? -> false or 1
@ -3303,6 +3334,7 @@ Init_Cont(void)
rb_eFiberError = rb_define_class("FiberError", rb_eStandardError);
rb_define_singleton_method(rb_cFiber, "yield", rb_fiber_s_yield, -1);
rb_define_singleton_method(rb_cFiber, "current", rb_fiber_s_current, 0);
rb_define_singleton_method(rb_cFiber, "blocking", rb_fiber_blocking, 0);
rb_define_method(rb_cFiber, "initialize", rb_fiber_initialize, -1);
rb_define_method(rb_cFiber, "blocking?", rb_fiber_blocking_p, 0);
rb_define_method(rb_cFiber, "resume", rb_fiber_m_resume, -1);

Просмотреть файл

@ -60,3 +60,20 @@ ruby_version_is "3.0" do
end
end
end
ruby_version_is "3.2" do
describe "Fiber.blocking" do
context "when fiber is non-blocking" do
it "can become blocking" do
fiber = Fiber.new(blocking: false) do
Fiber.blocking do |fiber|
fiber.blocking? ? :blocking : :non_blocking
end
end
blocking = fiber.resume
blocking.should == :blocking
end
end
end
end

Просмотреть файл

@ -27,6 +27,17 @@ class TestFiberScheduler < Test::Unit::TestCase
refute f.blocking?
end
def test_fiber_blocking
f = Fiber.new(blocking: false) do
fiber = Fiber.current
refute fiber.blocking?
Fiber.blocking do |_fiber|
assert_equal fiber, _fiber
assert fiber.blocking?
end
end
end
def test_closed_at_thread_exit
scheduler = Scheduler.new