2020-05-04 02:52:56 -04:00
|
|
|
#ifndef RBIMPL_INTERN_CONT_H /*-*-C++-*-vi:se ft=cpp:*/
|
|
|
|
#define RBIMPL_INTERN_CONT_H
|
2020-04-10 01:11:40 -04:00
|
|
|
/**
|
2020-04-08 00:28:13 -04:00
|
|
|
* @file
|
|
|
|
* @author Ruby developers <ruby-core@ruby-lang.org>
|
|
|
|
* @copyright This file is a part of the programming language Ruby.
|
|
|
|
* Permission is hereby granted, to either redistribute and/or
|
|
|
|
* modify this file, provided that the conditions mentioned in the
|
|
|
|
* file COPYING are met. Consult the file for details.
|
2020-05-04 03:27:48 -04:00
|
|
|
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
|
2020-04-08 00:28:13 -04:00
|
|
|
* implementation details. Don't take them as canon. They could
|
|
|
|
* rapidly appear then vanish. The name (path) of this header file
|
|
|
|
* is also an implementation detail. Do not expect it to persist
|
|
|
|
* at the place it is now. Developers are free to move it anywhere
|
|
|
|
* anytime at will.
|
|
|
|
* @note To ruby-core: remember that this header can be possibly
|
|
|
|
* recursively included from extension libraries written in C++.
|
|
|
|
* Do not expect for instance `__VA_ARGS__` is always available.
|
|
|
|
* We assume C99 for ruby itself but we don't assume languages of
|
2021-01-14 01:00:54 -05:00
|
|
|
* extension libraries. They could be written in C++98.
|
2020-04-08 00:28:13 -04:00
|
|
|
* @brief Public APIs related to rb_cFiber.
|
|
|
|
*/
|
2020-05-08 05:31:09 -04:00
|
|
|
#include "ruby/internal/dllexport.h"
|
|
|
|
#include "ruby/internal/value.h"
|
|
|
|
#include "ruby/internal/iterator.h"
|
2020-04-08 00:28:13 -04:00
|
|
|
|
2020-05-04 02:52:56 -04:00
|
|
|
RBIMPL_SYMBOL_EXPORT_BEGIN()
|
2020-04-08 00:28:13 -04:00
|
|
|
|
|
|
|
/* cont.c */
|
2021-05-12 20:49:20 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a Fiber instance from a C-backended block.
|
|
|
|
*
|
|
|
|
* @param[in] func A function, to become the fiber's body.
|
|
|
|
* @param[in] callback_obj Passed as-is to `func`.
|
|
|
|
* @return An allocated new instance of rb_cFiber, which is ready to be
|
|
|
|
* "resume"d.
|
|
|
|
*/
|
|
|
|
VALUE rb_fiber_new(rb_block_call_func_t func, VALUE callback_obj);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Queries the fiber which is calling this function. Any ruby execution
|
|
|
|
* context has its fiber, either explicitly or implicitly.
|
|
|
|
*
|
|
|
|
* @return The current fiber.
|
|
|
|
*/
|
2020-04-08 00:28:13 -04:00
|
|
|
VALUE rb_fiber_current(void);
|
|
|
|
|
2021-05-12 20:49:20 -04:00
|
|
|
/**
|
|
|
|
* Queries the liveness of the passed fiber. "Alive" in this context means
|
|
|
|
* that the fiber can still be resumed. Once it reaches is its end of
|
|
|
|
* execution, this function returns ::RUBY_Qfalse.
|
|
|
|
*
|
|
|
|
* @param[in] fiber A target fiber.
|
|
|
|
* @retval RUBY_Qtrue It is.
|
|
|
|
* @retval RUBY_Qfalse It isn't.
|
|
|
|
*/
|
|
|
|
VALUE rb_fiber_alive_p(VALUE fiber);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Queries if an object is a fiber.
|
|
|
|
*
|
|
|
|
* @param[in] obj Arbitrary ruby object.
|
|
|
|
* @retval RUBY_Qtrue It is.
|
|
|
|
* @retval RUBY_Qfalse It isn't.
|
|
|
|
*/
|
|
|
|
VALUE rb_obj_is_fiber(VALUE obj);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resumes the execution of the passed fiber, either from the point at which
|
|
|
|
* the last rb_fiber_yield() was called if any, or at the beginning of the
|
|
|
|
* fiber body if it is the first call to this function.
|
|
|
|
*
|
|
|
|
* Other arguments are passed into the fiber's body, either as return values of
|
|
|
|
* rb_fiber_yield() in case it switches to there, or as the block parameter of
|
|
|
|
* the fiber body if it switches to the beginning of the fiber.
|
|
|
|
*
|
|
|
|
* The return value of this function is either the value passed to previous
|
|
|
|
* rb_fiber_yield() call, or the ultimate evaluated value of the entire fiber
|
|
|
|
* body if the execution reaches the end of it.
|
|
|
|
*
|
|
|
|
* When an exception happens inside of a fiber it propagates to this function.
|
|
|
|
*
|
|
|
|
* ```ruby
|
|
|
|
* f = Fiber.new do |i|
|
|
|
|
* puts "<x> =>> #{i}"
|
|
|
|
* puts "<y> <-- #{i + 1}"
|
|
|
|
* j = Fiber.yield(i + 1)
|
|
|
|
* puts "<z> =>> #{j}"
|
|
|
|
* puts "<w> <-- #{j + 1}"
|
|
|
|
* next j + 1
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
* puts "[a] <-- 1"
|
|
|
|
* p = f.resume(1)
|
|
|
|
* puts "[b] =>> #{p}"
|
|
|
|
* puts "[c] <-- #{p + 1}"
|
|
|
|
* q = f.resume(p + 1)
|
|
|
|
* puts "[d] =>> #{q}"
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* Above program executes in `[a] <x> <y> [b] [c] <z> <w> [d]`.
|
|
|
|
*
|
|
|
|
* @param[out] fiber The fiber to resume.
|
|
|
|
* @param[in] argc Number of objects of `argv`.
|
|
|
|
* @param[in] argv Passed (somehow) to `fiber`.
|
|
|
|
* @exception rb_eFiberError `fib` is terminated etc.
|
|
|
|
* @exception rb_eException Any exceptions happen in `fiber`.
|
|
|
|
* @return (See above)
|
|
|
|
* @note This function _does_ return.
|
|
|
|
*
|
|
|
|
* @internal
|
|
|
|
*
|
|
|
|
* @shyouhei expected this function to raise ::rb_eFrozenError for frozen
|
|
|
|
* fibers but it doesn't in practice. Intentional or ...?
|
|
|
|
*/
|
2021-06-03 00:29:58 -04:00
|
|
|
VALUE rb_fiber_resume(VALUE fiber, int argc, const VALUE *argv);
|
2021-05-12 20:49:20 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Identical to rb_fiber_resume(), except you can specify how to handle the
|
|
|
|
* last element of the given array.
|
|
|
|
*
|
|
|
|
* @param[out] fiber The fiber to resume.
|
|
|
|
* @param[in] argc Number of objects of `argv`.
|
|
|
|
* @param[in] argv Passed (somehow) to `fiber`.
|
|
|
|
* @param[in] kw_splat Handling of keyword parameters:
|
|
|
|
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
|
|
|
|
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
|
|
|
|
* - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
|
|
|
|
* @exception rb_eFiberError `fiber` is terminated etc.
|
|
|
|
* @exception rb_eException Any exceptions happen in `fiber`.
|
|
|
|
* @return Either what was yielded or the last value of the fiber body.
|
|
|
|
*/
|
2021-06-03 00:29:58 -04:00
|
|
|
VALUE rb_fiber_resume_kw(VALUE fiber, int argc, const VALUE *argv, int kw_splat);
|
|
|
|
|
2021-05-12 20:49:20 -04:00
|
|
|
/**
|
|
|
|
* Yields the control back to the point where the current fiber was resumed.
|
|
|
|
* The passed objects would be the return value of rb_fiber_resume(). This
|
|
|
|
* fiber then suspends its execution until next time it is resumed.
|
|
|
|
*
|
|
|
|
* This function can also raise arbitrary exceptions injected from outside of
|
|
|
|
* the fiber, using `Fiber#raise` Ruby level API. There is no way to do that
|
|
|
|
* from C though.
|
|
|
|
*
|
|
|
|
* ```ruby
|
|
|
|
* exc = Class.new Exception
|
|
|
|
*
|
|
|
|
* f = Fiber.new do
|
|
|
|
* Fiber.yield
|
|
|
|
* rescue exc => e
|
|
|
|
* puts e.message
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
* f.resume
|
|
|
|
* f.raise exc, "Hi!"
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* @param[in] argc Number of objects of `argv`.
|
|
|
|
* @param[in] argv Passed to rb_fiber_resume().
|
|
|
|
* @exception rb_eException (See above)
|
|
|
|
* @return (See rb_fiber_resume() for details)
|
|
|
|
*
|
|
|
|
* @internal
|
|
|
|
*
|
|
|
|
* "There is no way to do that from C" is a lie. But @shyouhei doesn't think
|
|
|
|
* this very intentionally obfuscated way to raise arbitrary exceptions from C
|
|
|
|
* is an official C API. Extension libraries must not know this fact.
|
|
|
|
*/
|
2021-06-03 00:29:58 -04:00
|
|
|
VALUE rb_fiber_yield(int argc, const VALUE *argv);
|
2021-05-12 20:49:20 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Identical to rb_fiber_yield(), except you can specify how to handle the last
|
|
|
|
* element of the given array.
|
|
|
|
*
|
|
|
|
* @param[in] argc Number of objects of `argv`.
|
|
|
|
* @param[in] argv Passed to rb_fiber_resume().
|
|
|
|
* @param[in] kw_splat Handling of keyword parameters:
|
|
|
|
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
|
|
|
|
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
|
|
|
|
* - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
|
|
|
|
* @exception rb_eException What was raised using `Fiber#raise`.
|
|
|
|
* @return (See rb_fiber_resume() for details)
|
|
|
|
*/
|
2021-06-03 00:29:58 -04:00
|
|
|
VALUE rb_fiber_yield_kw(int argc, const VALUE *argv, int kw_splat);
|
|
|
|
|
2021-05-12 20:49:20 -04:00
|
|
|
/**
|
|
|
|
* Transfers 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 rb_fiber_yield().
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* The two style of control passing to and from fiber (one is rb_fiber_resume()
|
|
|
|
* and rb_fiber_yield(), another is rb_fiber_transfer() to and from fiber)
|
|
|
|
* can't be freely mixed.
|
|
|
|
*
|
|
|
|
* - If the Fiber's lifecycle had started with transfer, it will never be
|
|
|
|
* able to yield or be resumed control passing, only finish or transfer
|
|
|
|
* back. (It still can resume other fibers that are allowed to be
|
|
|
|
* resumed.)
|
|
|
|
*
|
|
|
|
* - If the Fiber's lifecycle had started with resume, it can yield or
|
|
|
|
* transfer to another Fiber, but can receive control back only the way
|
|
|
|
* compatible with the way it was given away: if it had transferred, it
|
|
|
|
* only can be transferred back, and if it had yielded, it only can be
|
|
|
|
* resumed back. After that, it again can transfer or yield.
|
|
|
|
*
|
|
|
|
* If those rules are broken, rb_eFiberError is raised.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* @param[out] fiber Explicit control destination.
|
|
|
|
* @param[in] argc Number of objects of `argv`.
|
|
|
|
* @param[in] argv Passed to rb_fiber_resume().
|
|
|
|
* @exception rb_eFiberError (See above)
|
|
|
|
* @exception rb_eException What was raised using `Fiber#raise`.
|
|
|
|
* @return (See rb_fiber_resume() for details)
|
|
|
|
*/
|
2021-06-03 00:29:58 -04:00
|
|
|
VALUE rb_fiber_transfer(VALUE fiber, int argc, const VALUE *argv);
|
2021-05-12 20:49:20 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Identical to rb_fiber_transfer(), except you can specify how to handle the
|
|
|
|
* last element of the given array.
|
|
|
|
*
|
|
|
|
* @param[out] fiber Explicit control destination.
|
|
|
|
* @param[in] argc Number of objects of `argv`.
|
|
|
|
* @param[in] argv Passed to rb_fiber_resume().
|
|
|
|
* @param[in] kw_splat Handling of keyword parameters:
|
|
|
|
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
|
|
|
|
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
|
|
|
|
* - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
|
|
|
|
* @exception rb_eFiberError (See above)
|
|
|
|
* @exception rb_eException What was raised using `Fiber#raise`.
|
|
|
|
* @return (See rb_fiber_resume() for details)
|
|
|
|
*/
|
2021-06-03 00:29:58 -04:00
|
|
|
VALUE rb_fiber_transfer_kw(VALUE fiber, int argc, const VALUE *argv, int kw_splat);
|
|
|
|
|
2021-07-13 21:42:18 -04:00
|
|
|
VALUE rb_fiber_raise(VALUE fiber, int argc, VALUE *argv);
|
|
|
|
|
2020-05-04 02:52:56 -04:00
|
|
|
RBIMPL_SYMBOL_EXPORT_END()
|
2020-04-08 00:28:13 -04:00
|
|
|
|
2020-05-04 02:52:56 -04:00
|
|
|
#endif /* RBIMPL_INTERN_CONT_H */
|