From cf1f9bdc8df2f4961e84b96b0534c12f02f2a507 Mon Sep 17 00:00:00 2001 From: Marc-Andre Lafortune Date: Thu, 24 Dec 2020 04:00:23 -0500 Subject: [PATCH] Language tweaks to Fiber [doc] --- cont.c | 103 +++++++++++++++++++++++++++------------------------------ 1 file changed, 48 insertions(+), 55 deletions(-) diff --git a/cont.c b/cont.c index a8250c3273..d2a347887b 100644 --- a/cont.c +++ b/cont.c @@ -1736,25 +1736,23 @@ rb_cont_call(int argc, VALUE *argv, VALUE contval) * * == Non-blocking Fibers * - * Since Ruby 3.0, the concept of non-blocking fiber was introduced. - * Non-blocking fiber, when reaching any potentially blocking operation (like - * sleep, wait for another process, wait for I/O data to be ready), instead - * of just freezing itself and all execution in the thread, yields control - * to other fibers, and allows the scheduler to handle waiting and waking - * (resuming) the fiber when it can proceed. + * The concept of non-blocking fiber was introduced in Ruby 3.0. + * A non-blocking fiber, when reaching a operation that would normally block + * the fiber (like sleep, or wait for another process or I/O) + # will yield control to other fibers and allow the scheduler to + # handle blocking and waking up (resuming) this fiber when it can proceed. * - * For Fiber to behave as non-blocking, it should be created in Fiber.new with - * blocking: false (which is the default now), and Fiber.scheduler + * For a Fiber to behave as non-blocking, it need to be created in Fiber.new with + * blocking: false (which is the default), and Fiber.scheduler * should be set with Fiber.set_scheduler. If Fiber.scheduler is not set in - * the current thread, blocking and non-blocking fiber's behavior is identical. + * the current thread, blocking and non-blocking fibers' behavior is identical. * * Ruby doesn't provide a scheduler class: it is expected to be implemented by * the user and correspond to Fiber::SchedulerInterface. * * There is also Fiber.schedule method, which is expected to immediately perform - * passed block in a non-blocking manner (but its actual implementation is up to - * the scheduler). - * + * the given block in a non-blocking manner. Its actual implementation is up to + * the scheduler. * */ @@ -1868,8 +1866,8 @@ rb_fiber_initialize_kw(int argc, VALUE* argv, VALUE self, int kw_splat) * call-seq: * Fiber.new(blocking: false) { |*args| ... } -> fiber * - * Creates new Fiber. Initially, fiber is not running, but can be resumed with - * #resume. Arguments to the first #resume call would be passed to the block: + * Creates new Fiber. Initially, the fiber is not running and can be resumed with + * #resume. Arguments to the first #resume call will be passed to the block: * * f = Fiber.new do |initial| * current = initial @@ -1883,9 +1881,9 @@ rb_fiber_initialize_kw(int argc, VALUE* argv, VALUE self, int kw_splat) * f.resume # prints: current: nil * # ... and so on ... * - * if blocking: false is passed to the Fiber.new, _and_ current thread - * has Fiber.scheduler defined, the Fiber becomes non-blocking (see "Non-blocking - * fibers" section in class docs). + * If blocking: false is passed to Fiber.new, _and_ current thread + * has a Fiber.scheduler defined, the Fiber becomes non-blocking (see "Non-blocking + * Fibers" section in class docs). */ static VALUE rb_fiber_initialize(int argc, VALUE* argv, VALUE self) @@ -1943,8 +1941,8 @@ rb_f_fiber_kw(int argc, VALUE* argv, int kw_splat) * I slept well * * ...e.g. on the first blocking operation inside the Fiber (sleep(1)), - * the control is yielded at the outside code (main fiber), and at the end - * of the execution, the scheduler takes care of properly resuming all the + * the control is yielded to the outside code (main fiber), and at the end + * of that execution, the scheduler takes care of properly resuming all the * blocked fibers. * * Note that the behavior described above is how the method is expected @@ -1966,8 +1964,9 @@ rb_f_fiber(int argc, VALUE *argv, VALUE obj) * call-seq: * Fiber.scheduler -> obj or nil * - * Fiber scheduler, set in the current thread with Fiber.set_scheduler. If the scheduler - * is +nil+ (which is the default), non-blocking fibers behavior is the same as blocking. + * Returns the Fiber scheduler, that was last set for the current thread with Fiber.set_scheduler. + * Returns +nil+ if no scheduler is set (which is the default), and non-blocking fibers' + # behavior is the same as blocking. * (see "Non-blocking fibers" section in class docs for details about the scheduler concept). * */ @@ -1981,7 +1980,7 @@ rb_fiber_scheduler(VALUE klass) * call-seq: * Fiber.set_scheduler(scheduler) -> scheduler * - * Sets Fiber scheduler for the current thread. If the scheduler is set, non-blocking + * Sets the Fiber scheduler for the current thread. If the scheduler is set, non-blocking * fibers (created by Fiber.new with blocking: false, or by Fiber.schedule) * call that scheduler's hook methods on potentially blocking operations, and the current * thread will call scheduler's +close+ method on finalization (allowing the scheduler to @@ -2314,7 +2313,7 @@ rb_fiber_transfer(VALUE fiber_value, int argc, const VALUE *argv) * Fiber is non-blocking if it was created via passing blocking: false * to Fiber.new, or via Fiber.schedule. * - * Note, that even if the method returns +false+, Fiber behaves differently + * Note that, even if the method returns +false+, the fiber behaves differently * only if Fiber.scheduler is set in the current thread. * * See the "Non-blocking fibers" section in class docs for details. @@ -2328,17 +2327,17 @@ rb_fiber_blocking_p(VALUE fiber) /* * call-seq: - * Fiber.blocking? -> false or number + * Fiber.blocking? -> false or 1 * * Returns +false+ if the current fiber is non-blocking. * Fiber is non-blocking if it was created via passing blocking: false * to Fiber.new, or via Fiber.schedule. * - * If the current Fiber is blocking, the method, unlike usual - * predicate methods, returns a *number* of blocking fibers currently - * running (TBD: always 1?). + * If the current Fiber is blocking, the method returns 1. + * Future developments may allow for situations where larger integers + * could be returned. * - * Note, that even if the method returns +false+, Fiber behaves differently + * Note that, even if the method returns +false+, Fiber behaves differently * only if Fiber.scheduler is set in the current thread. * * See the "Non-blocking fibers" section in class docs for details. @@ -2442,7 +2441,7 @@ rb_fiber_reset_root_local_storage(rb_thread_t *th) * * 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. You need to require 'fiber' + * always return +false+. You need to require 'fiber' * before using this method. */ VALUE @@ -2598,7 +2597,7 @@ rb_fiber_backtrace_locations(int argc, VALUE *argv, VALUE fiber) * Fiber.yield. You need to require 'fiber' * before using this method. * - * The fiber which receives the transfer call is treats it much like + * The fiber which receives the transfer call treats it much like * a resume call. Arguments passed to transfer are treated like those * passed to resume. * @@ -2619,8 +2618,8 @@ rb_fiber_backtrace_locations(int argc, VALUE *argv, VALUE fiber) * * If those rules are broken FiberError is raised. * - * For an individual Fiber design, yield/resume is more easy to use - * style (the Fiber just gives away control, it doesn't need to think + * For an individual Fiber design, yield/resume is easier to use + * (the Fiber just gives away control, it doesn't need to think * about who the control is given to), while transfer is more flexible * for complex cases, allowing to build arbitrary graphs of Fibers * dependent on each other. @@ -2710,7 +2709,7 @@ rb_fiber_s_yield(int argc, VALUE *argv, VALUE klass) /* * call-seq: - * Fiber.current() -> fiber + * Fiber.current -> fiber * * Returns the current fiber. You need to require 'fiber' * before using this method. If you are not running in the context of @@ -2722,14 +2721,6 @@ rb_fiber_s_current(VALUE klass) return rb_fiber_current(); } -/* - * call-seq: - * fiber.to_s -> string - * - * Returns fiber information string. - * - */ - static VALUE fiber_to_s(VALUE fiber_value) { @@ -2853,7 +2844,7 @@ rb_fiber_pool_initialize(int argc, VALUE* argv, VALUE self) * Document-class: Fiber::SchedulerInterface * * This is not an existing class, but documentation of the interface that Scheduler - * object should comply in order to be used as Fiber.scheduler and handle non-blocking + * object should comply to in order to be used as argument to Fiber.scheduler and handle non-blocking * fibers. See also the "Non-blocking fibers" section in Fiber class docs for explanations * of some concepts. * @@ -2862,19 +2853,19 @@ rb_fiber_pool_initialize(int argc, VALUE* argv, VALUE self) * * When the execution in the non-blocking Fiber reaches some blocking operation (like * sleep, wait for a process, or a non-ready I/O), it calls some of the scheduler's * hook methods, listed below. - * * Scheduler somehow registers what the current fiber is waited for, and yields control + * * Scheduler somehow registers what the current fiber is waiting on, and yields control * to other fibers with Fiber.yield (so the fiber would be suspended while expecting its * wait to end, and other fibers in the same thread can perform) * * At the end of the current thread execution, the scheduler's method #close is called * * The scheduler runs into a wait loop, checking all the blocked fibers (which it has - * registered on hook calls) and resuming them when the awaited resource is ready (I/O - * ready, sleep time passed). + * registered on hook calls) and resuming them when the awaited resource is ready + * (e.g. I/O ready or sleep time elapsed). * * A typical implementation would probably rely for this closing loop on a gem like * EventMachine[https://github.com/eventmachine/eventmachine] or * Async[https://github.com/socketry/async]. * - * This way concurrent execution will be achieved in a way that is transparent for every + * This way concurrent execution will be achieved transparently for every * individual Fiber's code. * * Hook methods are: @@ -2891,7 +2882,7 @@ rb_fiber_pool_initialize(int argc, VALUE* argv, VALUE self) * being created for the older Ruby version, the code which needs this hook will not fail, * and will just behave in a blocking fashion). * - * It is also strongly suggested that the scheduler implement the #fiber method, which is + * It is also strongly recommended that the scheduler implements the #fiber method, which is * delegated to by Fiber.schedule. * * Sample _toy_ implementation of the scheduler can be found in Ruby's code, in @@ -2931,7 +2922,7 @@ rb_fiber_scheduler_interface_close(VALUE self) * This hook is optional: if it is not present in the current scheduler, * Process::Status.wait will behave as a blocking method. * - * Expected to returns a Process::Status instance. + * Expected to return a Process::Status instance. */ static VALUE rb_fiber_scheduler_interface_process_wait(VALUE self) @@ -2968,9 +2959,9 @@ rb_fiber_scheduler_interface_io_wait(VALUE self) * * Invoked by Kernel#sleep and Mutex#sleep and is expected to provide * an implementation of sleeping in a non-blocking way. Implementation might - * register the current fiber in some list of "what fiber waits till what + * register the current fiber in some list of "which fiber wait until what * moment", call Fiber.yield to pass control, and then in #close resume - * the fibers whose wait period have ended. + * the fibers whose wait period has elapsed. * */ static VALUE @@ -2983,11 +2974,11 @@ rb_fiber_scheduler_interface_kernel_sleep(VALUE self) * call-seq: block(blocker, timeout = nil) * * Invoked by methods like Thread.join, and by Mutex, to signify that current - * Fiber is blocked till further notice (e.g. #unblock) or till +timeout+ will - * pass. + * Fiber is blocked until further notice (e.g. #unblock) or until +timeout+ has + * elapsed. * * +blocker+ is what we are waiting on, informational only (for debugging and - * logging). There are no guarantees about its value. + * logging). There are no guarantee about its value. * * Expected to return boolean, specifying whether the blocking operation was * successful or not. @@ -3020,12 +3011,14 @@ rb_fiber_scheduler_interface_unblock(VALUE self) * call-seq: fiber(&block) * * Implementation of the Fiber.schedule. The method is expected to immediately - * run passed block of code in a separate non-blocking fiber, and to return that Fiber. + * run the given block of code in a separate non-blocking fiber, and to return that Fiber. * * Minimal suggested implementation is: * * def fiber(&block) - * Fiber.new(blocking: false, &block).tap(&:resume) + * fiber = Fiber.new(blocking: false, &block) + * fiber.resume + * fiber * end */ static VALUE