ruby-changes:73872
From: Samuel <ko1@a...>
Date: Thu, 6 Oct 2022 19:01:11 +0900 (JST)
Subject: [ruby-changes:73872] e696ec67ac (master): Introduce `Fiber.blocking{}` for bypassing the fiber scheduler. (#6498)
https://git.ruby-lang.org/ruby.git/commit/?id=e696ec67ac From e696ec67ac7bd14ff8436f9ee7724c17c5bf6689 Mon Sep 17 00:00:00 2001 From: Samuel Williams <samuel.williams@o...> Date: Thu, 6 Oct 2022 23:00:49 +1300 Subject: Introduce `Fiber.blocking{}` for bypassing the fiber scheduler. (#6498) --- cont.c | 32 ++++++++++++++++++++++++++++++++ spec/ruby/core/fiber/blocking_spec.rb | 17 +++++++++++++++++ test/fiber/test_scheduler.rb | 11 +++++++++++ 3 files changed, 60 insertions(+) diff --git a/cont.c b/cont.c index 19e719ccd9..499e1e7910 100644 --- a/cont.c +++ b/cont.c @@ -2413,6 +2413,37 @@ rb_fiber_blocking_p(VALUE fiber) https://github.com/ruby/ruby/blob/trunk/cont.c#L2413 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) https://github.com/ruby/ruby/blob/trunk/cont.c#L3334 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 https://github.com/ruby/ruby/blob/trunk/spec/ruby/core/fiber/blocking_spec.rb#L60 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 https://github.com/ruby/ruby/blob/trunk/test/fiber/test_scheduler.rb#L27 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 -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/