[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]