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
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());
|
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:
|
* call-seq:
|
||||||
* fiber.raise -> obj
|
* 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
|
* 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
|
* +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+
|
* With no arguments, raises a +RuntimeError+. With a single +String+
|
||||||
* argument, raises a +RuntimeError+ with the string as a message. Otherwise,
|
* 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.
|
* blocks.
|
||||||
*/
|
*/
|
||||||
static VALUE
|
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);
|
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
|
static VALUE
|
||||||
@ -2422,6 +2435,12 @@ rb_fiber_backtrace_locations(int argc, VALUE *argv, VALUE fiber)
|
|||||||
*/
|
*/
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_fiber_m_transfer(int argc, VALUE *argv, VALUE fiber_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);
|
rb_fiber_t *fiber = fiber_ptr(fiber_value);
|
||||||
if (RTEST(fiber->resuming_fiber)) {
|
if (RTEST(fiber->resuming_fiber)) {
|
||||||
@ -2430,7 +2449,7 @@ rb_fiber_m_transfer(int argc, VALUE *argv, VALUE fiber_value)
|
|||||||
if (fiber->yielding) {
|
if (fiber->yielding) {
|
||||||
rb_raise(rb_eFiberError, "attempt to transfer to a yielding fiber");
|
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/)
|
-> { fiber.resume }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
@ -169,6 +169,16 @@ class TestFiber < Test::Unit::TestCase
|
|||||||
assert_equal(:ok, fib.raise)
|
assert_equal(:ok, fib.raise)
|
||||||
end
|
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
|
def test_transfer
|
||||||
ary = []
|
ary = []
|
||||||
f2 = nil
|
f2 = nil
|
||||||
|
Loading…
x
Reference in New Issue
Block a user