From 31e8de2920935d500105949bda931f3ca22cdbff Mon Sep 17 00:00:00 2001 From: "nicholas a. evans" Date: Tue, 17 Nov 2020 19:23:51 -0500 Subject: 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. --- cont.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'cont.c') diff --git a/cont.c b/cont.c index efa734d03a..bdc29e14c1 100644 --- a/cont.c +++ b/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); } /* -- cgit v1.2.3