mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Let Fiber#raise work with transferring fibers
This automatically choosess whether to use transfer on a transferring fiber or resume on a yielding fiber. If the fiber is resuming, it raises a FiberError.
This commit is contained in:
parent
e795b63246
commit
31e8de2920
Notes:
git
2020-12-12 06:18:45 +09:00
3 changed files with 58 additions and 4 deletions
27
cont.c
27
cont.c
|
@ -2330,6 +2330,8 @@ rb_fiber_m_resume(int argc, VALUE *argv, VALUE fiber)
|
|||
return rb_fiber_resume_kw(fiber, argc, argv, rb_keyword_given_p());
|
||||
}
|
||||
|
||||
static VALUE rb_fiber_transfer_kw(VALUE fiber_value, int argc, VALUE *argv, int kw_splat);
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* fiber.raise -> obj
|
||||
|
@ -2338,7 +2340,9 @@ rb_fiber_m_resume(int argc, VALUE *argv, VALUE fiber)
|
|||
*
|
||||
* Raises an exception in the fiber at the point at which the last
|
||||
* +Fiber.yield+ was called. If the fiber has not been started or has
|
||||
* already run to completion, raises +FiberError+.
|
||||
* already run to completion, raises +FiberError+. If the fiber is
|
||||
* yielding, it is resumed. If it is transferring, it is transferred into.
|
||||
* But if it is resuming, raises +FiberError+.
|
||||
*
|
||||
* With no arguments, raises a +RuntimeError+. With a single +String+
|
||||
* argument, raises a +RuntimeError+ with the string as a message. Otherwise,
|
||||
|
@ -2350,10 +2354,19 @@ rb_fiber_m_resume(int argc, VALUE *argv, VALUE fiber)
|
|||
* blocks.
|
||||
*/
|
||||
static VALUE
|
||||
rb_fiber_raise(int argc, VALUE *argv, VALUE fiber)
|
||||
rb_fiber_raise(int argc, VALUE *argv, VALUE fiber_value)
|
||||
{
|
||||
rb_fiber_t *fiber = fiber_ptr(fiber_value);
|
||||
VALUE exc = rb_make_exception(argc, argv);
|
||||
return rb_fiber_resume_kw(fiber, -1, &exc, RB_NO_KEYWORDS);
|
||||
if (RTEST(fiber->resuming_fiber)) {
|
||||
rb_raise(rb_eFiberError, "attempt to raise a resuming fiber");
|
||||
}
|
||||
else if (FIBER_SUSPENDED_P(fiber) && !fiber->yielding) {
|
||||
return rb_fiber_transfer_kw(fiber_value, -1, &exc, RB_NO_KEYWORDS);
|
||||
}
|
||||
else {
|
||||
return rb_fiber_resume_kw(fiber_value, -1, &exc, RB_NO_KEYWORDS);
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
|
@ -2422,6 +2435,12 @@ rb_fiber_backtrace_locations(int argc, VALUE *argv, VALUE fiber)
|
|||
*/
|
||||
static VALUE
|
||||
rb_fiber_m_transfer(int argc, VALUE *argv, VALUE fiber_value)
|
||||
{
|
||||
return rb_fiber_transfer_kw(fiber_value, argc, argv, rb_keyword_given_p());
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_fiber_transfer_kw(VALUE fiber_value, int argc, VALUE *argv, int kw_splat)
|
||||
{
|
||||
rb_fiber_t *fiber = fiber_ptr(fiber_value);
|
||||
if (RTEST(fiber->resuming_fiber)) {
|
||||
|
@ -2430,7 +2449,7 @@ rb_fiber_m_transfer(int argc, VALUE *argv, VALUE fiber_value)
|
|||
if (fiber->yielding) {
|
||||
rb_raise(rb_eFiberError, "attempt to transfer to a yielding fiber");
|
||||
}
|
||||
return fiber_switch(fiber, argc, argv, rb_keyword_given_p(), Qfalse, false);
|
||||
return fiber_switch(fiber, argc, argv, kw_splat, Qfalse, false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -73,4 +73,29 @@ ruby_version_is "2.7" do
|
|||
-> { fiber.resume }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
ruby_version_is "2.7"..."3.0" do
|
||||
describe "Fiber#raise" do
|
||||
it "raises a FiberError if invoked on a transferring Fiber" do
|
||||
require "fiber"
|
||||
root = Fiber.current
|
||||
fiber = Fiber.new { root.transfer }
|
||||
fiber.transfer
|
||||
-> { fiber.raise }.should raise_error(FiberError, "cannot resume transferred Fiber")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is "3.0" do
|
||||
describe "Fiber#raise" do
|
||||
it "transfers and raises on a transferring fiber" do
|
||||
require "fiber"
|
||||
root = Fiber.current
|
||||
fiber = Fiber.new { root.transfer }
|
||||
fiber.transfer
|
||||
-> { fiber.raise "msg" }.should raise_error(RuntimeError, "msg")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -169,6 +169,16 @@ class TestFiber < Test::Unit::TestCase
|
|||
assert_equal(:ok, fib.raise)
|
||||
end
|
||||
|
||||
def test_raise_transferring_fiber
|
||||
root = Fiber.current
|
||||
fib = Fiber.new { root.transfer }
|
||||
fib.transfer
|
||||
assert_raise(RuntimeError){
|
||||
fib.raise "can raise with transfer: true"
|
||||
}
|
||||
assert_not_predicate(fib, :alive?)
|
||||
end
|
||||
|
||||
def test_transfer
|
||||
ary = []
|
||||
f2 = nil
|
||||
|
|
Loading…
Add table
Reference in a new issue