diff options
author | Samuel Williams <[email protected]> | 2022-10-06 23:00:49 +1300 |
---|---|---|
committer | GitHub <[email protected]> | 2022-10-06 23:00:49 +1300 |
commit | e696ec67ac7bd14ff8436f9ee7724c17c5bf6689 (patch) | |
tree | f1388ed0cc30ceec2e5febf316c3897afa01b9ad | |
parent | 75a53f6be0bdd02fcf70a352892e085a02995cf9 (diff) |
Introduce `Fiber.blocking{}` for bypassing the fiber scheduler. (#6498)
Notes
Notes:
Merged-By: ioquatix <[email protected]>
-rw-r--r-- | cont.c | 32 | ||||
-rw-r--r-- | spec/ruby/core/fiber/blocking_spec.rb | 17 | ||||
-rw-r--r-- | test/fiber/test_scheduler.rb | 11 |
3 files changed, 60 insertions, 0 deletions
@@ -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); diff --git a/spec/ruby/core/fiber/blocking_spec.rb b/spec/ruby/core/fiber/blocking_spec.rb index 5ae5fbd577..852861d12f 100644 --- a/spec/ruby/core/fiber/blocking_spec.rb +++ b/spec/ruby/core/fiber/blocking_spec.rb @@ -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 diff --git a/test/fiber/test_scheduler.rb b/test/fiber/test_scheduler.rb index 4b1310f0a6..1d5881e233 100644 --- a/test/fiber/test_scheduler.rb +++ b/test/fiber/test_scheduler.rb @@ -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 |