mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
bf3b2a4374
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).
58 lines
1.6 KiB
Ruby
58 lines
1.6 KiB
Ruby
describe :fiber_resume, shared: true do
|
|
it "can be invoked from the root Fiber" do
|
|
fiber = Fiber.new { :fiber }
|
|
fiber.send(@method).should == :fiber
|
|
end
|
|
|
|
it "raises a FiberError if invoked from a different Thread" do
|
|
fiber = Fiber.new { 42 }
|
|
Thread.new do
|
|
-> {
|
|
fiber.send(@method)
|
|
}.should raise_error(FiberError)
|
|
end.join
|
|
|
|
# Check the Fiber can still be used
|
|
fiber.send(@method).should == 42
|
|
end
|
|
|
|
it "passes control to the beginning of the block on first invocation" do
|
|
invoked = false
|
|
fiber = Fiber.new { invoked = true }
|
|
fiber.send(@method)
|
|
invoked.should be_true
|
|
end
|
|
|
|
it "returns the last value encountered on first invocation" do
|
|
fiber = Fiber.new { 1+1; true }
|
|
fiber.send(@method).should be_true
|
|
end
|
|
|
|
it "runs until the end of the block" do
|
|
obj = mock('obj')
|
|
obj.should_receive(:do).once
|
|
fiber = Fiber.new { 1 + 2; a = "glark"; obj.do }
|
|
fiber.send(@method)
|
|
end
|
|
|
|
it "accepts any number of arguments" do
|
|
fiber = Fiber.new { |a| }
|
|
-> { fiber.send(@method, *(1..10).to_a) }.should_not raise_error
|
|
end
|
|
|
|
it "raises a FiberError if the Fiber is dead" do
|
|
fiber = Fiber.new { true }
|
|
fiber.send(@method)
|
|
-> { fiber.send(@method) }.should raise_error(FiberError)
|
|
end
|
|
|
|
it "raises a LocalJumpError if the block includes a return statement" do
|
|
fiber = Fiber.new { return; }
|
|
-> { fiber.send(@method) }.should raise_error(LocalJumpError)
|
|
end
|
|
|
|
it "raises a LocalJumpError if the block includes a break statement" do
|
|
fiber = Fiber.new { break; }
|
|
-> { fiber.send(@method) }.should raise_error(LocalJumpError)
|
|
end
|
|
end
|