mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
include/ruby/thread.h: add doxygen
Must not be a bad idea to improve documents. [ci skip]
This commit is contained in:
parent
53e0d7eec7
commit
a50287ab03
Notes:
git
2021-09-10 20:01:12 +09:00
1 changed files with 155 additions and 2 deletions
|
@ -10,19 +10,147 @@
|
|||
* modify this file, provided that the conditions mentioned in the
|
||||
* file COPYING are met. Consult the file for details.
|
||||
*/
|
||||
#include "ruby/intern.h"
|
||||
#include "ruby/internal/attr/nonnull.h"
|
||||
#include "ruby/internal/intern/thread.h" /* rb_unblock_function_t */
|
||||
#include "ruby/internal/dllexport.h"
|
||||
|
||||
/* flags for rb_nogvl */
|
||||
/**
|
||||
* @name Flags for rb_nogvl()
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Passing this flag to rb_nogvl() prevents it from checking interrupts.
|
||||
* Interrupts can impact your program negatively. For instance consider
|
||||
* following callback function:
|
||||
*
|
||||
* ```CXX
|
||||
* static inline int fd; // set elsewhere.
|
||||
* static inline auto callback(auto buf) {
|
||||
* auto tmp = ruby_xmalloc(BUFSIZ);
|
||||
* auto ret = ruby_xmalloc(sizeof(ssize_t)); // (a)
|
||||
* auto n = read(fd, tmp, BUFSIZ); // (b)
|
||||
* memcpy(buf, tmp, n); // (c)
|
||||
* memcpy(ret, n, sizeof(n));
|
||||
* ruby_xfree(tmp);
|
||||
* return ret;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Here, if it gets interrupted at (a) or (b), `read(2)` is cancelled and this
|
||||
* function leaks memory (which is not a good thing of course, but...). But if
|
||||
* it gets interrupted at (c), where `read(2)` is already done, interruption is
|
||||
* way more catastrophic because what was read gets lost. To reroute this kind
|
||||
* of problem you should set this flag. And check interrupts elsewhere at your
|
||||
* own risk.
|
||||
*/
|
||||
#define RB_NOGVL_INTR_FAIL (0x1)
|
||||
|
||||
/**
|
||||
* Passing this flag to rb_nogvl() indicates that the passed UBF is
|
||||
* async-signal-safe. An UBF could be async safe, and that makes things
|
||||
* simpler. However async unsafe UBFs are just okay. If unsure, you can
|
||||
* safely leave it unspecified.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* This makes sense only in case of POSIX threads.
|
||||
*/
|
||||
#define RB_NOGVL_UBF_ASYNC_SAFE (0x2)
|
||||
|
||||
/** @} */
|
||||
|
||||
RBIMPL_SYMBOL_EXPORT_BEGIN()
|
||||
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
/**
|
||||
* (Re-)acquires the GVL. This manoeuvre makes it possible for an out-of-GVL
|
||||
* routine to one-shot call a ruby method.
|
||||
*
|
||||
* What this function does:
|
||||
*
|
||||
* 1. Blocks until it acquires the GVL.
|
||||
* 2. Calls the passed function.
|
||||
* 3. Releases the GVL.
|
||||
* 4. Returns what was returned form the passed function.
|
||||
*
|
||||
* @param[in] func What to call with GVL.
|
||||
* @param[in,out] data1 Passed as-is to `func`.
|
||||
* @return What was returned from `func`.
|
||||
* @warning `func` must not return a Ruby object. If it did such return
|
||||
* value would escape from GC's scope; would not be marked.
|
||||
* @warning Global escapes from this function just yield whatever fatal
|
||||
* undefined behaviours. You must make sure that `func` does
|
||||
* not raise, by properly rescuing everything using
|
||||
* e.g. rb_protect().
|
||||
* @warning You cannot convert a non-Ruby thread into a Ruby thread
|
||||
* using this API. This function makes sense only from inside
|
||||
* of a rb_thread_call_without_gvl()'s callback.
|
||||
*/
|
||||
void *rb_thread_call_with_gvl(void *(*func)(void *), void *data1);
|
||||
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
/**
|
||||
* Allows the passed function to run in parallel with other Ruby threads.
|
||||
*
|
||||
* What this function does:
|
||||
*
|
||||
* 1. Checks (and handles) pending interrupts.
|
||||
* 2. Releases the GVL. (Others can run here in parallel...)
|
||||
* 3. Calls the passed function.
|
||||
* 4. Blocks until it re-acquires the GVL.
|
||||
* 5. Checks interrupts that happened between 2 to 4.
|
||||
*
|
||||
* In case other threads interfaced with this thread using rb_thread_kill()
|
||||
* etc., the passed UBF is additionally called. See ::rb_unblock_function_t
|
||||
* for details.
|
||||
*
|
||||
* Unlike rb_thread_call_without_gvl2() this function also reacts to signals
|
||||
* etc.
|
||||
*
|
||||
* @param[in] func A function to call without GVL.
|
||||
* @param[in,out] data1 Passed as-is to `func`.
|
||||
* @param[in] ubf An UBF to cancel `func`.
|
||||
* @param[in,out] data2 Passed as-is to `ubf`.
|
||||
* @return What `func` returned, or 0 in case `ubf` cancelled `func`.
|
||||
* @warning You cannot use most of Ruby C APIs like calling methods or
|
||||
* raising exceptions from any of the functions passed to it.
|
||||
* If that is dead necessary use rb_thread_call_with_gvl() to
|
||||
* re-acquire the GVL.
|
||||
* @warning In short, this API is difficult. @ko1 recommends you to use
|
||||
* other ways if any. We lack experiences to use this API. If
|
||||
* you find any corner cases etc., please report it to the
|
||||
* devs.
|
||||
* @warning Releasing and re-acquiring the GVL are expensive operations.
|
||||
* For a short-running `func`, it might be faster to just call
|
||||
* `func` with blocking everything else. Be sure to benchmark
|
||||
* your code to see if it is actually worth releasing the GVL.
|
||||
*/
|
||||
void *rb_thread_call_without_gvl(void *(*func)(void *), void *data1,
|
||||
rb_unblock_function_t *ubf, void *data2);
|
||||
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
/**
|
||||
* Identical to rb_thread_call_without_gvl(), except it does not interface with
|
||||
* signals etc. As described in #RB_NOGVL_INTR_FAIL, interrupts can hurt you.
|
||||
* In case this function detects an interrupt, it returns immediately. You can
|
||||
* record progress of your callback and check it after returning from this
|
||||
* function.
|
||||
*
|
||||
* What this function does:
|
||||
*
|
||||
* 1. Checks for pending interrupts and if any, just returns.
|
||||
* 2. Releases the GVL. (Others can run here in parallel...)
|
||||
* 3. Calls the passed function.
|
||||
* 4. Blocks until it re-acquires the GVL.
|
||||
*
|
||||
* @param[in] func A function to call without GVL.
|
||||
* @param[in,out] data1 Passed as-is to `func`.
|
||||
* @param[in] ubf An UBF to cancel `func`.
|
||||
* @param[in,out] data2 Passed as-is to `ubf`.
|
||||
* @return What `func` returned, or 0 in case `func` did not return.
|
||||
*/
|
||||
void *rb_thread_call_without_gvl2(void *(*func)(void *), void *data1,
|
||||
rb_unblock_function_t *ubf, void *data2);
|
||||
|
||||
|
@ -30,11 +158,36 @@ void *rb_thread_call_without_gvl2(void *(*func)(void *), void *data1,
|
|||
* XXX: unstable/unapproved - out-of-tree code should NOT not depend
|
||||
* on this until it hits Ruby 2.6.1
|
||||
*/
|
||||
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
/**
|
||||
* Identical to rb_thread_call_without_gvl(), except it additionally takes
|
||||
* "flags" that change the behaviour.
|
||||
*
|
||||
* @param[in] func A function to call without GVL.
|
||||
* @param[in,out] data1 Passed as-is to `func`.
|
||||
* @param[in] ubf An UBF to cancel `func`.
|
||||
* @param[in,out] data2 Passed as-is to `ubf`.
|
||||
* @param[in] flags Flags.
|
||||
* @return What `func` returned, or 0 in case `func` did not return.
|
||||
*/
|
||||
void *rb_nogvl(void *(*func)(void *), void *data1,
|
||||
rb_unblock_function_t *ubf, void *data2,
|
||||
int flags);
|
||||
|
||||
/**
|
||||
* @private
|
||||
*
|
||||
* @deprecated This macro once was a thing in the old days, but makes no sense
|
||||
* any longer today. Exists here for backwards compatibility
|
||||
* only. You can safely forget about it.
|
||||
*/
|
||||
#define RUBY_CALL_WO_GVL_FLAG_SKIP_CHECK_INTS_AFTER 0x01
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @deprecated It seems even in the old days it made no sense...?
|
||||
*/
|
||||
#define RUBY_CALL_WO_GVL_FLAG_SKIP_CHECK_INTS_
|
||||
|
||||
RBIMPL_SYMBOL_EXPORT_END()
|
||||
|
|
Loading…
Reference in a new issue