diff options
Diffstat (limited to 'include/ruby/internal/intern/thread.h')
| -rw-r--r-- | include/ruby/internal/intern/thread.h | 492 |
1 files changed, 0 insertions, 492 deletions
diff --git a/include/ruby/internal/intern/thread.h b/include/ruby/internal/intern/thread.h deleted file mode 100644 index 716375acd7..0000000000 --- a/include/ruby/internal/intern/thread.h +++ /dev/null @@ -1,492 +0,0 @@ -#ifndef RBIMPL_INTERN_THREAD_H /*-*-C++-*-vi:se ft=cpp:*/ -#define RBIMPL_INTERN_THREAD_H -/** - * @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. - * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are - * 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 - * extension libraries. They could be written in C++98. - * @brief Public APIs related to ::rb_cThread. - */ -#include "ruby/internal/attr/nonnull.h" -#include "ruby/internal/cast.h" -#include "ruby/internal/config.h" -#include "ruby/internal/dllexport.h" -#include "ruby/internal/value.h" - -RBIMPL_SYMBOL_EXPORT_BEGIN() - -struct timeval; - -/* thread.c */ - -/** - * Tries to switch to another thread. This function blocks until the current - * thread re-acquires the GVL. - * - * @exception rb_eInterrupt Operation interrupted. - */ -void rb_thread_schedule(void); - -/** - * Blocks the current thread until the given file descriptor is ready to be - * read. - * - * @param[in] fd A file descriptor. - * @exception rb_eIOError Closed stream. - * @exception rb_eSystemCallError Situations like EBADF. - */ -int rb_thread_wait_fd(int fd); - -/** - * Identical to rb_thread_wait_fd(), except it blocks the current thread until - * the given file descriptor is ready to be written. - * - * @param[in] fd A file descriptor. - * @exception rb_eIOError Closed stream. - * @exception rb_eSystemCallError Situations like EBADF. - */ -int rb_thread_fd_writable(int fd); - -/** - * Notifies a closing of a file descriptor to other threads. Multiple threads - * can wait for the given file descriptor at once. If such file descriptor is - * closed, threads need to start propagating their exceptions. This is the API - * to kick that process. - * - * @param[in] fd A file descriptor. - * @note This function blocks until all the threads waiting for such fd - * have woken up. - */ -void rb_thread_fd_close(int fd); - -/** - * Checks if the thread this function is running is the only thread that is - * currently alive. - * - * @retval 1 Yes it is. - * @retval 0 No it isn't. - * - * @internal - * - * Above description is in fact inaccurate. There are Ractors these days. - */ -int rb_thread_alone(void); - -/** - * Blocks for the given period of time. - * - * @warning This function can be interrupted by signals. - * @param[in] sec Duration in seconds. - * @exception rb_eInterrupt Interrupted. - */ -void rb_thread_sleep(int sec); - -/** - * Blocks indefinitely. - * - * @exception rb_eInterrupt Interrupted. - */ -void rb_thread_sleep_forever(void); - -/** - * Identical to rb_thread_sleep_forever(), except the thread calling this - * function is considered "dead" when our deadlock checker is triggered. - * - * @exception rb_eInterrupt Interrupted. - */ -void rb_thread_sleep_deadly(void); - -/** - * Stops the current thread. This is not the end of the thread's lifecycle. A - * stopped thread can later be woken up. - * - * @exception rb_eThreadError Stopping this thread would deadlock. - * @retval ::RUBY_Qnil Always. - * - * @internal - * - * The return value makes no sense at all. - */ -VALUE rb_thread_stop(void); - -/** - * Marks a given thread as eligible for scheduling. - * - * @note It may still remain blocked on I/O. - * @note This does not invoke the scheduler itself. - * - * @param[out] thread Thread in question to wake up. - * @exception rb_eThreadError Stop flogging a dead horse. - * @return The passed thread. - * @post The passed thread is made runnable. - */ -VALUE rb_thread_wakeup(VALUE thread); - -/** - * Identical to rb_thread_wakeup(), except it doesn't raise on an already - * killed thread. - * - * @param[out] thread A thread to wake up. - * @retval RUBY_Qnil `thread` is already killed. - * @retval otherwise `thread` is alive. - * @post The passed thread is made runnable, unless killed. - */ -VALUE rb_thread_wakeup_alive(VALUE thread); - -/** - * This is a rb_thread_wakeup() + rb_thread_schedule() combo. - * - * @note There is no guarantee that this function yields to the passed - * thread. It may still remain blocked on I/O. - * @param[out] thread Thread in question to wake up. - * @exception rb_eThreadError Stop flogging a dead horse. - * @return The passed thread. - */ -VALUE rb_thread_run(VALUE thread); - -/** - * Terminates the given thread. Unlike a stopped thread, a killed thread could - * never be revived. This function does return, when passed e.g. an already - * killed thread. But if the passed thread is the only one, or a special - * thread called "main", then it also terminates the entire process. - * - * @param[out] thread The thread to terminate. - * @exception rb_eFatal The passed thread is the running thread. - * @exception rb_eSystemExit The passed thread is the last thread. - * @return The passed thread. - * @post Either the passed thread, or the process entirely, is killed. - * - * @internal - * - * It seems killing the main thread also kills the entire process even if there - * are multiple running ractors. No idea why. - */ -VALUE rb_thread_kill(VALUE thread); - -RBIMPL_ATTR_NONNULL((1)) -/** - * Creates a Ruby thread that is backended by a C function. - * - * @param[in] f The function to run on a thread. - * @param[in,out] g Passed through to `f`. - * @exception rb_eThreadError Could not create a ruby thread. - * @exception rb_eSystemCallError Situations like `EPERM`. - * @return Allocated instance of ::rb_cThread. - * @note This doesn't wait for anything. - */ -VALUE rb_thread_create(VALUE (*f)(void *g), void *g); - -/** - * Identical to rb_thread_sleep(), except it takes struct `timeval` instead. - * - * @warning This function can be interrupted by signals. - * @param[in] time Duration. - * @exception rb_eInterrupt Interrupted. - */ -void rb_thread_wait_for(struct timeval time); - -/** - * Obtains the "current" thread. - * - * @return The current thread of the current ractor of the current execution - * context. - * @pre This function must be called from a thread controlled by ruby. - */ -VALUE rb_thread_current(void); - -/** - * Obtains the "main" thread. There are threads called main. Historically the - * (only) main thread was the one which runs when the process boots. Now that - * we have Ractor, there are more than one main threads. - * - * @return The main thread of the current ractor of the current execution - * context. - * @pre This function must be called from a thread controlled by ruby. - */ -VALUE rb_thread_main(void); - -/** - * This badly named function reads from a Fiber local storage. When this - * function was born there was no such thing like a Fiber. The world was - * innocent. But now... This is a Fiber local storage. Sorry. - * - * @param[in] thread Thread that the target Fiber is running. - * @param[in] key The name of the Fiber local storage to read. - * @retval RUBY_Qnil No such storage. - * @retval otherwise The value stored at `key`. - * @note There in fact are "true" thread local storage, but Ruby doesn't - * provide any interface of them to you, C programmers. - */ -VALUE rb_thread_local_aref(VALUE thread, ID key); - -/** - * This badly named function writes to a Fiber local storage. When this - * function was born there was no such thing like a Fiber. The world was - * innocent. But now... This is a Fiber local storage. Sorry. - * - * @param[in] thread Thread that the target Fiber is running. - * @param[in] key The name of the Fiber local storage to write. - * @param[in] val The new value of the storage. - * @exception rb_eFrozenError `thread` is frozen. - * @return The passed `val` as-is. - * @post Fiber local storage `key` has value of `val`. - * @note There in fact are "true" thread local storage, but Ruby doesn't - * provide any interface of them to you, C programmers. - */ -VALUE rb_thread_local_aset(VALUE thread, ID key, VALUE val); - -/** - * A `pthread_atfork(3posix)`-like API. Ruby expects its child processes to - * call this function at the very beginning of their processes. If you plan to - * fork a process don't forget to call it. - */ -void rb_thread_atfork(void); - -/** - * :FIXME: situation of this function is unclear. It seems nobody uses it. - * Maybe a good idea to KonMari. - */ -void rb_thread_atfork_before_exec(void); - -/** - * "Recursion" API entry point. This basically calls the given function with - * the given arguments, but additionally with recursion flag. The flag is set - * to 1 if the execution have already experienced the passed `g` parameter - * before. - * - * @param[in] f The function that possibly recurs. - * @param[in,out] g Passed as-is to `f`. - * @param[in,out] h Passed as-is to `f`. - * @return The return value of f. - */ -VALUE rb_exec_recursive(VALUE (*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h); - -/** - * Identical to rb_exec_recursive(), except it checks for the recursion on the - * ordered pair of `{ g, p }` instead of just `g`. - * - * @param[in] f The function that possibly recurs. - * @param[in,out] g Passed as-is to `f`. - * @param[in] p Paired object for recursion detection. - * @param[in,out] h Passed as-is to `f`. - */ -VALUE rb_exec_recursive_paired(VALUE (*f)(VALUE g, VALUE h, int r), VALUE g, VALUE p, VALUE h); - -/** - * Identical to rb_exec_recursive(), except it calls `f` for outermost - * recursion only. Inner recursions yield calls to rb_throw_obj(). - * - * @param[in] f The function that possibly recurs. - * @param[in,out] g Passed as-is to `f`. - * @param[in,out] h Passed as-is to `f`. - * @return The return value of f. - * - * @internal - * - * It seems nobody uses the "it calls rb_throw_obj()" part of this function. - * @shyouhei doesn't understand the needs. - */ -VALUE rb_exec_recursive_outer(VALUE (*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h); - -/** - * Identical to rb_exec_recursive_outer(), except it checks for the recursion - * on the ordered pair of `{ g, p }` instead of just `g`. It can also be seen - * as a routine identical to rb_exec_recursive_paired(), except it calls `f` - * for outermost recursion only. Inner recursions yield calls to - * rb_throw_obj(). - * - * @param[in] f The function that possibly recurs. - * @param[in,out] g Passed as-is to `f`. - * @param[in] p Paired object for recursion detection. - * @param[in,out] h Passed as-is to `f`. - * - * @internal - * - * It seems nobody uses the "it calls rb_throw_obj()" part of this function. - * @shyouhei doesn't understand the needs. - */ -VALUE rb_exec_recursive_paired_outer(VALUE (*f)(VALUE g, VALUE h, int r), VALUE g, VALUE p, VALUE h); - -/** - * This is the type of UBFs. An UBF is a function that unblocks a blocking - * region. For instance when a thread is blocking due to `pselect(3posix)`, it - * is highly expected that `pthread_kill(3posix)` can interrupt the system call - * and the thread could revive. Or when a thread is blocking due to - * `waitpid(3posix)`, it is highly expected that killing the waited process - * should suffice. An UBF is a function that does such things. Designing your - * own UBF needs deep understanding of why your blocking region blocks, how - * threads work in ruby, and a matter of luck. It often is the case you simply - * cannot cancel something that had already begun. - * - * @see rb_thread_call_without_gvl() - */ -typedef void rb_unblock_function_t(void *); - -/** - * @private - * - * This is an implementation detail. Must be a mistake to be here. - * - * @internal - * - * Why is this function type different from what rb_thread_call_without_gvl() - * takes? - */ -typedef VALUE rb_blocking_function_t(void *); - -/** - * Checks for interrupts. In ruby, signals are masked by default. You can - * call this function at will to check if there are pending signals. In case - * there are, they would be handled in this function. - * - * If your extension library has a function that takes a long time, consider - * calling it periodically. - * - * @note It might switch to another thread. - */ -void rb_thread_check_ints(void); - -/** - * Checks if the thread's execution was recently interrupted. If called from - * that thread, this function can be used to detect spurious wake-ups. - * - * @param[in] thval Thread in question. - * @retval 0 The thread was not interrupted. - * @retval otherwise The thread was interrupted recently. - * - * @internal - * - * Above description is not a lie. But actually the return value is an opaque - * trap vector. If you know which bit means which, you can know what happened. - */ -int rb_thread_interrupted(VALUE thval); - -/** - * A special UBF for blocking IO operations. You need deep understanding of - * what this actually do before using. Basically you should not use it from - * extension libraries. It is too easy to mess up. - */ -#define RUBY_UBF_IO RBIMPL_CAST((rb_unblock_function_t *)-1) - -/** - * A special UBF for blocking process operations. You need deep understanding - * of what this actually do before using. Basically you should not use it from - * extension libraries. It is too easy to mess up. - */ -#define RUBY_UBF_PROCESS RBIMPL_CAST((rb_unblock_function_t *)-1) - -/* thread_sync.c */ - -/** - * Creates a mutex. - * - * @return An allocated instance of rb_cMutex. - */ -VALUE rb_mutex_new(void); - -/** - * Queries if there are any threads that holds the lock. - * - * @param[in] mutex The mutex in question. - * @retval RUBY_Qtrue The mutex is locked by someone. - * @retval RUBY_Qfalse The mutex is not locked by anyone. - */ -VALUE rb_mutex_locked_p(VALUE mutex); - -/** - * Attempts to lock the mutex, without waiting for other threads to unlock it. - * Failure in locking the mutex can be detected by the return value. - * - * @param[out] mutex The mutex to lock. - * @retval RUBY_Qtrue Successfully locked by the current thread. - * @retval RUBY_Qfalse Otherwise. - * @note This function also returns ::RUBY_Qfalse when the mutex is - * already owned by the calling thread itself. - */ -VALUE rb_mutex_trylock(VALUE mutex); - -/** - * Attempts to lock the mutex. It waits until the mutex gets available. - * - * @param[out] mutex The mutex to lock. - * @exception rb_eThreadError Recursive deadlock situation. - * @return The passed mutex. - * @post The mutex is owned by the current thread. - */ -VALUE rb_mutex_lock(VALUE mutex); - -/** - * Releases the mutex. - * - * @param[out] mutex The mutex to unlock. - * @exception rb_eThreadError The mutex is not owned by the current thread. - * @return The passed mutex. - * @post Upon successful return the passed mutex is no longer owned by - * the current thread. - */ -VALUE rb_mutex_unlock(VALUE mutex); - -/** - * Releases the lock held in the mutex and waits for the period of time; - * reacquires the lock on wakeup. - * - * @pre The lock has to be owned by the current thread beforehand. - * @param[out] self The target mutex. - * @param[in] timeout Duration, in seconds, in ::rb_cNumeric. - * @exception rb_eArgError `timeout` is negative. - * @exception rb_eRangeError `timeout` is out of range of `time_t`. - * @exception rb_eThreadError The mutex is not owned by the current thread. - * @return Number of seconds it actually slept. - * @warning It is a failure not to check the return value. This function - * can return spuriously for various reasons. Maybe other threads - * can rb_thread_wakeup(). Maybe an end user can press the - * Control and C key from the interactive console. On the other - * hand it can also take longer than the specified. The mutex - * could be locked by someone else. It waits then. - * @post Upon successful return the passed mutex is owned by the current - * thread. - * - * @internal - * - * This function is called from `ConditionVariable#wait`. So it is not a - * deprecated feature. However @shyouhei have never seen any similar mutex - * primitive available in any other languages than Ruby. - * - * EDIT: In 2021, @shyouhei asked @ko1 in person about this API. He answered - * that it is his invention. The motivation behind its design is to eliminate - * needs of condition variables as primitives. Unlike other languages, Ruby's - * `ConditionVariable` class was written in pure-Ruby initially. We don't have - * to implement machine-native condition variables in assembly each time we - * port Ruby to a new architecture. This function made it possible. "I felt I - * was a genius when this idea came to me", said @ko1. - * - * `rb_cConditionVariable` is now written in C for speed, though. - */ -VALUE rb_mutex_sleep(VALUE self, VALUE timeout); - -/** - * Obtains the lock, runs the passed function, and releases the lock when it - * completes. - * - * @param[out] mutex The mutex to lock. - * @param[in] func What to do during the mutex is locked. - * @param[in,out] arg Passed as-is to `func`. - */ -VALUE rb_mutex_synchronize(VALUE mutex, VALUE (*func)(VALUE arg), VALUE arg); - -RBIMPL_SYMBOL_EXPORT_END() - -#endif /* RBIMPL_INTERN_THREAD_H */ |
