mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Expose rb_fiber_raise
and tidy up the internal implementation.
This commit is contained in:
parent
2e3d43e577
commit
88ba5fe547
Notes:
git
2021-09-20 15:31:11 +09:00
2 changed files with 96 additions and 71 deletions
165
cont.c
165
cont.c
|
@ -235,7 +235,7 @@ struct rb_fiber_struct {
|
||||||
rb_context_t cont;
|
rb_context_t cont;
|
||||||
VALUE first_proc;
|
VALUE first_proc;
|
||||||
struct rb_fiber_struct *prev;
|
struct rb_fiber_struct *prev;
|
||||||
VALUE resuming_fiber;
|
struct rb_fiber_struct *resuming_fiber;
|
||||||
|
|
||||||
BITFIELD(enum fiber_status, status, 2);
|
BITFIELD(enum fiber_status, status, 2);
|
||||||
/* Whether the fiber is allowed to implicitly yield. */
|
/* Whether the fiber is allowed to implicitly yield. */
|
||||||
|
@ -2174,7 +2174,7 @@ return_fiber(bool terminate)
|
||||||
|
|
||||||
if (prev) {
|
if (prev) {
|
||||||
fiber->prev = NULL;
|
fiber->prev = NULL;
|
||||||
prev->resuming_fiber = Qnil;
|
prev->resuming_fiber = NULL;
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -2188,9 +2188,7 @@ return_fiber(bool terminate)
|
||||||
VM_ASSERT(root_fiber != NULL);
|
VM_ASSERT(root_fiber != NULL);
|
||||||
|
|
||||||
// search resuming fiber
|
// search resuming fiber
|
||||||
for (fiber = root_fiber;
|
for (fiber = root_fiber; fiber->resuming_fiber; fiber = fiber->resuming_fiber) {
|
||||||
RTEST(fiber->resuming_fiber);
|
|
||||||
fiber = fiber_ptr(fiber->resuming_fiber)) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return fiber;
|
return fiber;
|
||||||
|
@ -2231,7 +2229,7 @@ fiber_store(rb_fiber_t *next_fiber, rb_thread_t *th)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline VALUE
|
static inline VALUE
|
||||||
fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, VALUE resuming_fiber, bool yielding)
|
fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, rb_fiber_t *resuming_fiber, bool yielding)
|
||||||
{
|
{
|
||||||
VALUE value;
|
VALUE value;
|
||||||
rb_context_t *cont = &fiber->cont;
|
rb_context_t *cont = &fiber->cont;
|
||||||
|
@ -2278,8 +2276,9 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, VALUE
|
||||||
|
|
||||||
rb_fiber_t *current_fiber = fiber_current();
|
rb_fiber_t *current_fiber = fiber_current();
|
||||||
|
|
||||||
VM_ASSERT(!RTEST(current_fiber->resuming_fiber));
|
VM_ASSERT(!current_fiber->resuming_fiber);
|
||||||
if (RTEST(resuming_fiber)) {
|
|
||||||
|
if (resuming_fiber) {
|
||||||
current_fiber->resuming_fiber = resuming_fiber;
|
current_fiber->resuming_fiber = resuming_fiber;
|
||||||
fiber->prev = fiber_current();
|
fiber->prev = fiber_current();
|
||||||
fiber->yielding = 0;
|
fiber->yielding = 0;
|
||||||
|
@ -2302,7 +2301,7 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, VALUE
|
||||||
|
|
||||||
// We cannot free the stack until the pthread is joined:
|
// We cannot free the stack until the pthread is joined:
|
||||||
#ifndef COROUTINE_PTHREAD_CONTEXT
|
#ifndef COROUTINE_PTHREAD_CONTEXT
|
||||||
if (RTEST(resuming_fiber) && FIBER_TERMINATED_P(fiber)) {
|
if (resuming_fiber && FIBER_TERMINATED_P(fiber)) {
|
||||||
fiber_stack_release(fiber);
|
fiber_stack_release(fiber);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2324,7 +2323,7 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, VALUE
|
||||||
VALUE
|
VALUE
|
||||||
rb_fiber_transfer(VALUE fiber_value, int argc, const VALUE *argv)
|
rb_fiber_transfer(VALUE fiber_value, int argc, const VALUE *argv)
|
||||||
{
|
{
|
||||||
return fiber_switch(fiber_ptr(fiber_value), argc, argv, RB_NO_KEYWORDS, Qfalse, false);
|
return fiber_switch(fiber_ptr(fiber_value), argc, argv, RB_NO_KEYWORDS, NULL, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2399,15 +2398,14 @@ rb_fiber_terminate(rb_fiber_t *fiber, int need_interrupt, VALUE error)
|
||||||
if (need_interrupt) RUBY_VM_SET_INTERRUPT(&next_fiber->cont.saved_ec);
|
if (need_interrupt) RUBY_VM_SET_INTERRUPT(&next_fiber->cont.saved_ec);
|
||||||
|
|
||||||
if (RTEST(error))
|
if (RTEST(error))
|
||||||
fiber_switch(next_fiber, -1, &error, RB_NO_KEYWORDS, Qfalse, false);
|
fiber_switch(next_fiber, -1, &error, RB_NO_KEYWORDS, NULL, false);
|
||||||
else
|
else
|
||||||
fiber_switch(next_fiber, 1, &value, RB_NO_KEYWORDS, Qfalse, false);
|
fiber_switch(next_fiber, 1, &value, RB_NO_KEYWORDS, NULL, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
static VALUE
|
||||||
rb_fiber_resume_kw(VALUE fiber_value, int argc, const VALUE *argv, int kw_splat)
|
fiber_resume_kw(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat)
|
||||||
{
|
{
|
||||||
rb_fiber_t *fiber = fiber_ptr(fiber_value);
|
|
||||||
rb_fiber_t *current_fiber = fiber_current();
|
rb_fiber_t *current_fiber = fiber_current();
|
||||||
|
|
||||||
if (argc == -1 && FIBER_CREATED_P(fiber)) {
|
if (argc == -1 && FIBER_CREATED_P(fiber)) {
|
||||||
|
@ -2422,7 +2420,7 @@ rb_fiber_resume_kw(VALUE fiber_value, int argc, const VALUE *argv, int kw_splat)
|
||||||
else if (fiber->prev != NULL) {
|
else if (fiber->prev != NULL) {
|
||||||
rb_raise(rb_eFiberError, "attempt to resume a resumed fiber (double resume)");
|
rb_raise(rb_eFiberError, "attempt to resume a resumed fiber (double resume)");
|
||||||
}
|
}
|
||||||
else if (RTEST(fiber->resuming_fiber)) {
|
else if (fiber->resuming_fiber) {
|
||||||
rb_raise(rb_eFiberError, "attempt to resume a resuming fiber");
|
rb_raise(rb_eFiberError, "attempt to resume a resuming fiber");
|
||||||
}
|
}
|
||||||
else if (fiber->prev == NULL &&
|
else if (fiber->prev == NULL &&
|
||||||
|
@ -2430,27 +2428,33 @@ rb_fiber_resume_kw(VALUE fiber_value, int argc, const VALUE *argv, int kw_splat)
|
||||||
rb_raise(rb_eFiberError, "attempt to resume a transferring fiber");
|
rb_raise(rb_eFiberError, "attempt to resume a transferring fiber");
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE result = fiber_switch(fiber, argc, argv, kw_splat, fiber_value, false);
|
VALUE result = fiber_switch(fiber, argc, argv, kw_splat, fiber, false);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_fiber_resume(VALUE fiber_value, int argc, const VALUE *argv)
|
rb_fiber_resume_kw(VALUE self, int argc, const VALUE *argv, int kw_splat)
|
||||||
{
|
{
|
||||||
return rb_fiber_resume_kw(fiber_value, argc, argv, RB_NO_KEYWORDS);
|
return fiber_resume_kw(fiber_ptr(self), argc, argv, kw_splat);
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_fiber_resume(VALUE self, int argc, const VALUE *argv)
|
||||||
|
{
|
||||||
|
return fiber_resume_kw(fiber_ptr(self), argc, argv, RB_NO_KEYWORDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_fiber_yield_kw(int argc, const VALUE *argv, int kw_splat)
|
rb_fiber_yield_kw(int argc, const VALUE *argv, int kw_splat)
|
||||||
{
|
{
|
||||||
return fiber_switch(return_fiber(false), argc, argv, kw_splat, Qfalse, true);
|
return fiber_switch(return_fiber(false), argc, argv, kw_splat, NULL, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_fiber_yield(int argc, const VALUE *argv)
|
rb_fiber_yield(int argc, const VALUE *argv)
|
||||||
{
|
{
|
||||||
return fiber_switch(return_fiber(false), argc, argv, RB_NO_KEYWORDS, Qfalse, true);
|
return fiber_switch(return_fiber(false), argc, argv, RB_NO_KEYWORDS, NULL, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -2496,43 +2500,6 @@ 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());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq:
|
|
||||||
* fiber.raise -> obj
|
|
||||||
* fiber.raise(string) -> obj
|
|
||||||
* fiber.raise(exception [, string [, array]]) -> obj
|
|
||||||
*
|
|
||||||
* 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+. 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,
|
|
||||||
* the first parameter should be the name of an +Exception+ class (or an
|
|
||||||
* object that returns an +Exception+ object when sent an +exception+
|
|
||||||
* message). The optional second parameter sets the message associated with
|
|
||||||
* the exception, and the third parameter is an array of callback information.
|
|
||||||
* Exceptions are caught by the +rescue+ clause of <code>begin...end</code>
|
|
||||||
* blocks.
|
|
||||||
*/
|
|
||||||
static VALUE
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* fiber.backtrace -> array
|
* fiber.backtrace -> array
|
||||||
|
@ -2693,22 +2660,29 @@ 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 self)
|
||||||
{
|
{
|
||||||
return rb_fiber_transfer_kw(fiber_value, argc, argv, rb_keyword_given_p());
|
return rb_fiber_transfer_kw(self, argc, argv, rb_keyword_given_p());
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
fiber_transfer_kw(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat)
|
||||||
|
{
|
||||||
|
if (fiber->resuming_fiber) {
|
||||||
|
rb_raise(rb_eFiberError, "attempt to transfer to a resuming fiber");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fiber->yielding) {
|
||||||
|
rb_raise(rb_eFiberError, "attempt to transfer to a yielding fiber");
|
||||||
|
}
|
||||||
|
|
||||||
|
return fiber_switch(fiber, argc, argv, kw_splat, NULL, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_fiber_transfer_kw(VALUE fiber_value, int argc, const VALUE *argv, int kw_splat)
|
rb_fiber_transfer_kw(VALUE self, int argc, const VALUE *argv, int kw_splat)
|
||||||
{
|
{
|
||||||
rb_fiber_t *fiber = fiber_ptr(fiber_value);
|
return fiber_transfer_kw(fiber_ptr(self), argc, argv, kw_splat);
|
||||||
if (RTEST(fiber->resuming_fiber)) {
|
|
||||||
rb_raise(rb_eFiberError, "attempt to transfer to a resuming fiber");
|
|
||||||
}
|
|
||||||
if (fiber->yielding) {
|
|
||||||
rb_raise(rb_eFiberError, "attempt to transfer to a yielding fiber");
|
|
||||||
}
|
|
||||||
return fiber_switch(fiber, argc, argv, kw_splat, Qfalse, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2727,6 +2701,55 @@ rb_fiber_s_yield(int argc, VALUE *argv, VALUE klass)
|
||||||
return rb_fiber_yield_kw(argc, argv, rb_keyword_given_p());
|
return rb_fiber_yield_kw(argc, argv, rb_keyword_given_p());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
fiber_raise(rb_fiber_t *fiber, int argc, VALUE *argv)
|
||||||
|
{
|
||||||
|
VALUE exception = rb_make_exception(argc, argv);
|
||||||
|
|
||||||
|
if (fiber->resuming_fiber) {
|
||||||
|
rb_raise(rb_eFiberError, "attempt to raise a resuming fiber");
|
||||||
|
}
|
||||||
|
else if (FIBER_SUSPENDED_P(fiber) && !fiber->yielding) {
|
||||||
|
return fiber_transfer_kw(fiber, -1, &exception, RB_NO_KEYWORDS);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return fiber_resume_kw(fiber, -1, &exception, RB_NO_KEYWORDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_fiber_raise(VALUE fiber, int argc, VALUE *argv)
|
||||||
|
{
|
||||||
|
return fiber_raise(fiber_ptr(fiber), argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* fiber.raise -> obj
|
||||||
|
* fiber.raise(string) -> obj
|
||||||
|
* fiber.raise(exception [, string [, array]]) -> obj
|
||||||
|
*
|
||||||
|
* 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+. 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,
|
||||||
|
* the first parameter should be the name of an +Exception+ class (or an
|
||||||
|
* object that returns an +Exception+ object when sent an +exception+
|
||||||
|
* message). The optional second parameter sets the message associated with
|
||||||
|
* the exception, and the third parameter is an array of callback information.
|
||||||
|
* Exceptions are caught by the +rescue+ clause of <code>begin...end</code>
|
||||||
|
* blocks.
|
||||||
|
*/
|
||||||
|
static VALUE
|
||||||
|
rb_fiber_m_raise(int argc, VALUE *argv, VALUE self)
|
||||||
|
{
|
||||||
|
return rb_fiber_raise(self, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* Fiber.current -> fiber
|
* Fiber.current -> fiber
|
||||||
|
@ -2747,7 +2770,7 @@ fiber_to_s(VALUE fiber_value)
|
||||||
const rb_proc_t *proc;
|
const rb_proc_t *proc;
|
||||||
char status_info[0x20];
|
char status_info[0x20];
|
||||||
|
|
||||||
if (RTEST(fiber->resuming_fiber)) {
|
if (fiber->resuming_fiber) {
|
||||||
snprintf(status_info, 0x20, " (%s by resuming)", fiber_status_name(fiber->status));
|
snprintf(status_info, 0x20, " (%s by resuming)", fiber_status_name(fiber->status));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -3081,7 +3104,7 @@ Init_Cont(void)
|
||||||
rb_define_method(rb_cFiber, "initialize", rb_fiber_initialize, -1);
|
rb_define_method(rb_cFiber, "initialize", rb_fiber_initialize, -1);
|
||||||
rb_define_method(rb_cFiber, "blocking?", rb_fiber_blocking_p, 0);
|
rb_define_method(rb_cFiber, "blocking?", rb_fiber_blocking_p, 0);
|
||||||
rb_define_method(rb_cFiber, "resume", rb_fiber_m_resume, -1);
|
rb_define_method(rb_cFiber, "resume", rb_fiber_m_resume, -1);
|
||||||
rb_define_method(rb_cFiber, "raise", rb_fiber_raise, -1);
|
rb_define_method(rb_cFiber, "raise", rb_fiber_m_raise, -1);
|
||||||
rb_define_method(rb_cFiber, "backtrace", rb_fiber_backtrace, -1);
|
rb_define_method(rb_cFiber, "backtrace", rb_fiber_backtrace, -1);
|
||||||
rb_define_method(rb_cFiber, "backtrace_locations", rb_fiber_backtrace_locations, -1);
|
rb_define_method(rb_cFiber, "backtrace_locations", rb_fiber_backtrace_locations, -1);
|
||||||
rb_define_method(rb_cFiber, "to_s", fiber_to_s, 0);
|
rb_define_method(rb_cFiber, "to_s", fiber_to_s, 0);
|
||||||
|
|
|
@ -239,6 +239,8 @@ VALUE rb_fiber_transfer(VALUE fiber, int argc, const VALUE *argv);
|
||||||
*/
|
*/
|
||||||
VALUE rb_fiber_transfer_kw(VALUE fiber, int argc, const VALUE *argv, int kw_splat);
|
VALUE rb_fiber_transfer_kw(VALUE fiber, int argc, const VALUE *argv, int kw_splat);
|
||||||
|
|
||||||
|
VALUE rb_fiber_raise(VALUE fiber, int argc, VALUE *argv);
|
||||||
|
|
||||||
RBIMPL_SYMBOL_EXPORT_END()
|
RBIMPL_SYMBOL_EXPORT_END()
|
||||||
|
|
||||||
#endif /* RBIMPL_INTERN_CONT_H */
|
#endif /* RBIMPL_INTERN_CONT_H */
|
||||||
|
|
Loading…
Add table
Reference in a new issue