summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cont.c29
-rw-r--r--test/ruby/test_fiber.rb40
2 files changed, 69 insertions, 0 deletions
diff --git a/cont.c b/cont.c
index da469b6cd5..dcf6b01db8 100644
--- a/cont.c
+++ b/cont.c
@@ -1228,6 +1228,8 @@ static VALUE
make_passing_arg(int argc, const VALUE *argv)
{
switch (argc) {
+ case -1:
+ return argv[0];
case 0:
return Qnil;
case 1:
@@ -1956,6 +1958,32 @@ rb_fiber_m_resume(int argc, VALUE *argv, VALUE fib)
/*
* 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
+ * <code>Fiber.yield</code> was called, or at the start if neither +resume+
+ * nor +raise+ were called before.
+ *
+ * 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 fib)
+{
+ VALUE exc = rb_make_exception(argc, argv);
+ return rb_fiber_resume(fib, -1, &exc);
+}
+
+/*
+ * call-seq:
* fiber.transfer(args, ...) -> obj
*
* Transfer control to another fiber, resuming it from where it last
@@ -2112,6 +2140,7 @@ Init_Cont(void)
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);
rb_define_method(rb_cFiber, "to_s", fiber_to_s, 0);
rb_define_alias(rb_cFiber, "inspect", "to_s");
}
diff --git a/test/ruby/test_fiber.rb b/test/ruby/test_fiber.rb
index 84d668c988..db2627d9a1 100644
--- a/test/ruby/test_fiber.rb
+++ b/test/ruby/test_fiber.rb
@@ -109,6 +109,15 @@ class TestFiber < Test::Unit::TestCase
}
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
@@ -127,6 +136,37 @@ class TestFiber < Test::Unit::TestCase
}
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