Fiber#transfer previously made it impossible to resume the fiber
if it was transferred to (no resuming the target of Fiber#transfer).
However, the documentation specifies that you cannot resume a fiber
that has transferred to another fiber (no resuming the source of
Fiber#transfer), unless control is transferred back.

Fix the code by setting the transferred flag on the current/source
fiber, and unsetting the transferred flag on the target fiber.

Fixes [Bug #9664]
Fixes [Bug #12555]
This commit is contained in:
Jeremy Evans 2019-10-21 16:54:58 -07:00 коммит произвёл GitHub
Родитель f37cc1c719
Коммит fa8ac91e95
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 18 добавлений и 10 удалений

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

@ -2226,7 +2226,8 @@ static VALUE
rb_fiber_m_transfer(int argc, VALUE *argv, VALUE fiber_value)
{
rb_fiber_t *fiber = fiber_ptr(fiber_value);
fiber->transferred = 1;
fiber_current()->transferred = 1;
fiber->transferred = 0;
return fiber_switch(fiber, argc, argv, 0, PASS_KW_SPLAT);
}

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

@ -42,9 +42,18 @@ describe "Fiber#transfer" do
fiber2.transfer.should == [:fiber2_start, :fiber1, :fiber2_end]
end
it "raises a FiberError when transferring to a Fiber which resumes itself" do
fiber = Fiber.new { fiber.resume }
-> { fiber.transfer }.should raise_error(FiberError)
ruby_version_is ''...'2.7' do
it "raises a FiberError when transferring to a Fiber which resumes itself" do
fiber = Fiber.new { fiber.resume }
-> { fiber.transfer }.should raise_error(FiberError)
end
end
ruby_version_is '2.7' do
it "allows transferring to a Fiber which resumes itself" do
fiber = Fiber.new { fiber.resume 1 }
fiber.transfer.should == 1
end
end
it "works if Fibers in different Threads each transfer to a Fiber in the same Thread" do

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

@ -222,8 +222,8 @@ class TestFiber < Test::Unit::TestCase
end
def test_resume_self
f = Fiber.new {f.resume}
assert_raise(FiberError, '[ruby-core:23651]') {f.transfer}
f = Fiber.new {f.resume 1}
assert_equal(1, f.transfer)
end
def test_fiber_transfer_segv
@ -289,14 +289,12 @@ class TestFiber < Test::Unit::TestCase
assert_raise(FiberError){
g=nil
f=Fiber.new{
g.resume
g.resume
g.transfer
}
g=Fiber.new{
f.resume
f.resume
}
f.transfer
f.resume
}
end