Feature #10344 » 0001-Implement-Fiber-raise.patch
cont.c | ||
---|---|---|
make_passing_arg(int argc, const VALUE *argv)
|
||
{
|
||
switch (argc) {
|
||
case -1:
|
||
return argv[0];
|
||
case 0:
|
||
return Qnil;
|
||
case 1:
|
||
... | ... | |
/*
|
||
* call-seq:
|
||
* fiber.raise(string) -> obj
|
||
* fiber.raise(exception [, string [, array]]) -> obj
|
||
*
|
||
* Assuming that <code>resume</code> was called before, raises an exception in
|
||
* the fiber at the point at which the last <code>Fiber.yield</code> was
|
||
* called. If the <code>Fiber.yield</code> occurs within a
|
||
* <code>begin...end</code> block with a +rescue+ clause matching the
|
||
* exception being raised, <code>fiber.raise</code> evaluates to the arguments
|
||
* passed to the next <code>Fiber.yield</code> statement inside the fiber's
|
||
* block or to the block value if it runs to completion without any
|
||
* <code>Fiber.yield</code>. Otherwise, the exception is propagated to the
|
||
* caller.
|
||
*
|
||
* If the fiber either has never been resumed or is dead, raises FiberError.
|
||
*
|
||
* 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.
|
||
*/
|
||
static VALUE
|
||
rb_fiber_raise(int argc, VALUE *argv, VALUE fibval)
|
||
{
|
||
VALUE exc;
|
||
rb_fiber_t *fib;
|
||
GetFiberPtr(fibval, fib);
|
||
switch(fib->status) {
|
||
case CREATED:
|
||
rb_raise(rb_eFiberError, "Cannot raise exception in an unborn fiber."
|
||
" You need to resume first.");
|
||
case RUNNING:
|
||
exc = rb_make_exception(argc, argv);
|
||
return rb_fiber_resume(fibval, -1, &exc);
|
||
case TERMINATED:
|
||
rb_raise(rb_eFiberError, "Cannot raise exception in a dead fiber.");
|
||
}
|
||
return Qundef;
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* fiber.transfer(args, ...) -> obj
|
||
*
|
||
* Transfer control to another fiber, resuming it from where it last
|
||
... | ... | |
rb_define_singleton_method(rb_cFiber, "yield", rb_fiber_s_yield, -1);
|
||
rb_define_method(rb_cFiber, "initialize", rb_fiber_init, 0);
|
||
rb_define_method(rb_cFiber, "resume", rb_fiber_m_resume, -1);
|
||
rb_define_method(rb_cFiber, "raise", rb_fiber_raise, -1);
|
||
}
|
||
RUBY_SYMBOL_EXPORT_BEGIN
|
test/ruby/test_fiber.rb | ||
---|---|---|
}
|
||
fib.resume
|
||
}
|
||
assert_raise(FiberError){
|
||
fib = Fiber.new{}
|
||
fib.raise "raise in unborn fiber"
|
||
}
|
||
assert_raise(FiberError){
|
||
fib = Fiber.new{}
|
||
fib.resume
|
||
fib.raise "raise in dead fiber"
|
||
}
|
||
end
|
||
def test_return
|
||
... | ... | |
}
|
||
end
|
||
def test_raise
|
||
assert_raise(ZeroDivisionError){
|
||
Fiber.new do
|
||
1/0
|
||
end.resume
|
||
}
|
||
assert_raise(RuntimeError){
|
||
fib = Fiber.new{ Fiber.yield }
|
||
fib.raise "raise and propagate"
|
||
}
|
||
assert_nothing_raised{
|
||
fib = Fiber.new do
|
||
begin
|
||
Fiber.yield
|
||
rescue
|
||
end
|
||
end
|
||
fib.resume
|
||
fib.raise "rescue in fiber"
|
||
}
|
||
fib = Fiber.new do
|
||
begin
|
||
Fiber.yield
|
||
rescue
|
||
Fiber.yield :ok
|
||
end
|
||
end
|
||
fib.resume
|
||
assert_equal(:ok, fib.raise)
|
||
end
|
||
def test_transfer
|
||
ary = []
|
||
f2 = nil
|