From 9125374726fbf68c05ee7585d4a374ffc5efc5db Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Thu, 27 Jan 2022 17:12:22 +0100 Subject: [Feature #18339] GVL Instrumentation API Ref: https://bugs.ruby-lang.org/issues/18339 Design: - This tries to minimize the overhead when no hook is registered. It should only incur an extra unsynchronized boolean check. - The hook list is protected with a read-write lock as to cause contention when some hooks are registered. - The hooks MUST be thread safe, and MUST NOT call into Ruby as they are executed outside the GVL. - It's simply a noop on Windows. API: ``` rb_internal_thread_event_hook_t * rb_internal_thread_add_event_hook(rb_internal_thread_event_callback callback, rb_event_flag_t internal_event, void *user_data); bool rb_internal_thread_remove_event_hook(rb_internal_thread_event_hook_t * hook); ``` You can subscribe to 3 events: - READY: called right before attempting to acquire the GVL - RESUMED: called right after successfully acquiring the GVL - SUSPENDED: called right after releasing the GVL. The hooks MUST be threadsafe, as they are executed outside of the GVL, they also MUST NOT call any Ruby API. --- include/ruby/thread.h | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'include') diff --git a/include/ruby/thread.h b/include/ruby/thread.h index 18c792b386..7f9e623fe5 100644 --- a/include/ruby/thread.h +++ b/include/ruby/thread.h @@ -190,6 +190,44 @@ void *rb_nogvl(void *(*func)(void *), void *data1, */ #define RUBY_CALL_WO_GVL_FLAG_SKIP_CHECK_INTS_ +#define RUBY_INTERNAL_THREAD_EVENT_READY 0x01 /** acquiring GVL */ +#define RUBY_INTERNAL_THREAD_EVENT_RESUMED 0x02 /** acquired GVL */ +#define RUBY_INTERNAL_THREAD_EVENT_SUSPENDED 0x04 /** released GVL */ +#define RUBY_INTERNAL_THREAD_EVENT_MASK 0x07 /** All Thread events */ + +typedef void rb_internal_thread_event_data_t; // for future extension. + +typedef void (*rb_internal_thread_event_callback)(rb_event_flag_t event, + const rb_internal_thread_event_data_t *event_data, + void *user_data); +typedef struct rb_internal_thread_event_hook rb_internal_thread_event_hook_t; + +/** + * Registers a thread event hook function. + * + * @param[in] func A callback. + * @param[in] events A set of events that `func` should run. + * @param[in] data Passed as-is to `func`. + * @return An opaque pointer to the hook, to unregister it later. + * @note This functionality is a noop on Windows. + * @warning This function MUST not be called from a thread event callback. + */ +rb_internal_thread_event_hook_t *rb_internal_thread_add_event_hook( + rb_internal_thread_event_callback func, rb_event_flag_t events, + void *data); + + +/** + * Unregister the passed hook. + * + * @param[in] hook. The hook to unregister. + * @return Wether the hook was found and unregistered. + * @note This functionality is a noop on Windows. + * @warning This function MUST not be called from a thread event callback. +*/ +bool rb_internal_thread_remove_event_hook( + rb_internal_thread_event_hook_t * hook); + RBIMPL_SYMBOL_EXPORT_END() #endif /* RUBY_THREAD_H */ -- cgit v1.2.3