summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2020-10-08 01:15:32 +0900
committerKoichi Sasada <ko1@atdot.net>2020-10-12 22:58:41 +0900
commitbf3b2a43741e4f72be21bc6acf24d37e7fcff61c (patch)
treed5c320990b7b1077aea78b5b111a945086073f8e /test
parent2fd71112fb5b1aafa5b243c7ac5713cfae7fc23c (diff)
relax Fiber#transfer's restriction
Using Fiber#transfer with Fiber#resume for a same Fiber is limited (once Fiber#transfer is called for a fiber, the fiber can not be resumed more). This restriction was introduced to protect the resume/yield chain, but we realized that it is too much to protect the chain. Instead of the current restriction, we introduce some other protections. (1) can not transfer to the resuming fiber. (2) can not transfer to the yielding fiber. (3) can not resume transferred fiber. (4) can not yield from not-resumed fiber. [Bug #17221] Also at the end of a transferred fiber, it had continued on root fiber. However, if the root fiber resumed a fiber (and that fiber can resumed another fiber), this behavior also breaks the resume/yield chain. So at the end of a transferred fiber, switch to the edge of resume chain from root fiber. For example, root fiber resumed f1 and f1 resumed f2, transferred to f3 and f3 terminated, then continue from the fiber f2 (it was continued from root fiber without this patch).
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/3636
Diffstat (limited to 'test')
-rw-r--r--test/ruby/test_fiber.rb103
1 files changed, 87 insertions, 16 deletions
diff --git a/test/ruby/test_fiber.rb b/test/ruby/test_fiber.rb
index 4d103a7f76..dc46b558f0 100644
--- a/test/ruby/test_fiber.rb
+++ b/test/ruby/test_fiber.rb
@@ -184,6 +184,34 @@ class TestFiber < Test::Unit::TestCase
assert_equal([:baz], ary)
end
+ def test_terminate_transferred_fiber
+ root_fiber = Fiber.current
+ log = []
+ fa1 = fa2 = fb1 = r1 = nil
+
+ fa1 = Fiber.new{
+ fa2 = Fiber.new{
+ log << :fa2_terminate
+ }
+ fa2.resume
+ log << :fa1_terminate
+ }
+ fb1 = Fiber.new{
+ fa1.transfer
+ log << :fb1_terminate
+ }
+
+ r1 = Fiber.new{
+ fb1.transfer
+ log << :r1_terminate
+ }
+
+ r1.resume
+ log << :root_terminate
+
+ assert_equal [:fa2_terminate, :fa1_terminate, :r1_terminate, :root_terminate], log
+ end
+
def test_tls
#
def tvar(var, val)
@@ -278,29 +306,72 @@ class TestFiber < Test::Unit::TestCase
assert_instance_of(Class, Fiber.new(&Class.new.method(:undef_method)).resume(:to_s), bug5083)
end
- def test_prohibit_resume_transferred_fiber
+ def test_prohibit_transfer_to_resuming_fiber
+ root_fiber = Fiber.current
+
assert_raise(FiberError){
- root_fiber = Fiber.current
- f = Fiber.new{
- root_fiber.transfer
- }
- f.transfer
- f.resume
+ fiber = Fiber.new{ root_fiber.transfer }
+ fiber.resume
+ }
+
+ fa1 = Fiber.new{
+ fa2 = Fiber.new{ root_fiber.transfer }
+ }
+ fb1 = Fiber.new{
+ fb2 = Fiber.new{ root_fiber.transfer }
+ }
+ fa1.transfer
+ fb1.transfer
+
+ assert_raise(FiberError){
+ fa1.transfer
}
assert_raise(FiberError){
- g=nil
- f=Fiber.new{
- g.resume
- g.resume
- }
- g=Fiber.new{
- f.resume
- f.resume
+ fb1.transfer
+ }
+ end
+
+ def test_prohibit_transfer_to_yielding_fiber
+ root_fiber = Fiber.current
+ f1 = f2 = f3 = nil
+
+ f1 = Fiber.new{
+ f2 = Fiber.new{
+ f3 = Fiber.new{
+ p f3: Fiber.yield
+ }
+ f3.resume
}
- f.transfer
+ f2.resume
}
+ f1.resume
+
+ assert_raise(FiberError){ f3.transfer 10 }
end
+ def test_prohibit_resume_to_transferring_fiber
+ root_fiber = Fiber.current
+
+ assert_raise(FiberError){
+ Fiber.new{
+ root_fiber.resume
+ }.transfer
+ }
+
+ f1 = f2 = nil
+ f1 = Fiber.new do
+ f2.transfer
+ end
+ f2 = Fiber.new do
+ f1.resume # attempt to resume transferring fiber
+ end
+
+ assert_raise(FiberError){
+ f1.transfer
+ }
+ end
+
+
def test_fork_from_fiber
skip 'fork not supported' unless Process.respond_to?(:fork)
pid = nil