summaryrefslogtreecommitdiff
path: root/cont.c
diff options
context:
space:
mode:
authoryugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-12-27 00:25:47 +0000
committeryugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-12-27 00:25:47 +0000
commit57363127157b6a697b61f04a3ba205152135538e (patch)
tree397168f7790ab74161d100aa7e7aff0345827a26 /cont.c
parent2d5061bd98a59fc1b9a477074f8f7a3500db8342 (diff)
* cont.c: rdoc for Fiber. patch by Muhammad Ali.
[ruby-core:20894] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@21077 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'cont.c')
-rw-r--r--cont.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/cont.c b/cont.c
index 10912e4c35..22c7fb3720 100644
--- a/cont.c
+++ b/cont.c
@@ -570,6 +570,68 @@ rb_cont_call(int argc, VALUE *argv, VALUE contval)
/* fiber */
/*********/
+/*
+ * Document-class: Fiber
+ *
+ * Fibers are primitives for implementing light weight cooperative
+ * concurrency in Ruby. Basically they are a means of creating code blocks
+ * that can be paused and resumed, much like threads. The main difference
+ * is that they are never preempted and that the scheduling must be done by
+ * the programmer and not the VM.
+ *
+ * As opposed to other stackless light weight concurrency models, each fiber
+ * comes with a small 4KB stack. This enables the fiber to be paused from deeply
+ * nested function calls within the fiber block.
+ *
+ * When a fiber is created it will not run automatically. Rather it must be
+ * be explicitly asked to run using the <code>Fiber#resume</code> method.
+ * The code running inside the fiber can give up control by calling
+ * <code>Fiber.yield</code> in which case it yields control back to caller
+ * (the caller of the <code>Fiber#resume</code>).
+ *
+ * Upon yielding or termination the Fiber returns the value of the last
+ * executed expression
+ *
+ * For instance:
+ *
+ * fiber = Fiber.new do
+ * Fiber.yield 1
+ * 2
+ * end
+ *
+ * puts fiber.resume
+ * puts fiber.resume
+ * puts fiber.resume
+ *
+ * <em>produces</em>
+ *
+ * 1
+ * 2
+ * FiberError: dead fiber called
+ *
+ * The <code>Fiber#resume</code> method accepts an arbitary number of
+ * parameters, if it is the first call to <code>resume</code> then they
+ * will be passed as block arguments. Other wise they will be the return
+ * value of the call to <code>Fiber.yield</code>
+ *
+ * Example:
+ *
+ * fiber = Fiber.new do |first|
+ * second = Fiber.yield first + 2
+ * end
+ *
+ * puts fiber.resume 10
+ * puts fiber.resume 14
+ * puts fiber.resume 18
+ *
+ * <em>produces</em>
+ *
+ * 12
+ * 14
+ * FiberError: dead fiber called
+ *
+ */
+
#define FIBER_VM_STACK_SIZE (4 * 1024)
static VALUE
@@ -840,6 +902,14 @@ rb_fiber_yield(int argc, VALUE *argv)
return rb_fiber_transfer(return_fiber(), argc, argv);
}
+/*
+ * call-seq:
+ * fiber.alive? -> true or false
+ *
+ * Returns true if the fiber can still be resumed (or transferred to).
+ * After finishing execution of the fiber block this method will always
+ * return false.
+ */
VALUE
rb_fiber_alive_p(VALUE fibval)
{
@@ -848,24 +918,73 @@ rb_fiber_alive_p(VALUE fibval)
return fib->status != TERMINATED;
}
+/*
+ * call-seq:
+ * fiber.resume(args, ...) -> obj
+ *
+ * Resumes the fiber from the point at which the last <code>Fiber.yield</code>
+ * was called, or starts running it if it is the first call to
+ * <code>resume</code>. Arguments passed to resume will be the value of
+ * the <code>Fiber.yield</code> expression or will be passed as block
+ * parameters to the fiber's block if this is the first <code>resume</code>.
+ *
+ * Alternatively, when resume is called it 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>
+ */
static VALUE
rb_fiber_m_resume(int argc, VALUE *argv, VALUE fib)
{
return rb_fiber_resume(fib, argc, argv);
}
+/*
+ * call-seq:
+ * fiber.transfer(args, ...) -> obj
+ *
+ * Transfer control to another fiber, resuming it from where it last
+ * stopped or starting it if it was not resumed before. The calling
+ * fiber will be suspended much like in a call to <code>Fiber.yield</code>.
+ *
+ * The fiber which recieves the transfer call is treats it much like
+ * a resume call. Arguments passed to transfer are treated like those
+ * passed to resume.
+ *
+ * You cannot resume a fiber that transferred control to another one.
+ * This will cause a double resume error. You need to transfer control
+ * back to this fiber before it can yield and resume.
+ */
static VALUE
rb_fiber_m_transfer(int argc, VALUE *argv, VALUE fib)
{
return rb_fiber_transfer(fib, argc, argv);
}
+/*
+ * call-seq:
+ * Fiber.yield(args, ...) -> obj
+ *
+ * Yields control back to the context that resumed the fiber, passing
+ * along any arguments that were passed to it. The fiber will resume
+ * processing at this point when <code>resume</code> is called next.
+ * Any arguments passed to the next <code>resume</code> will be the
+ * value that this <code>Fiber.yield</code> expression evaluates to.
+ */
static VALUE
rb_fiber_s_yield(int argc, VALUE *argv, VALUE klass)
{
return rb_fiber_yield(argc, argv);
}
+/*
+ * call-seq:
+ * Fiber.current() -> fiber
+ *
+ * Returns the current fiber. You need to <code>require 'fiber'</code>
+ * before using this method. If you are not running in the context of
+ * a fiber this method will return the root fiber.
+ */
static VALUE
rb_fiber_s_current(VALUE klass)
{