From c3fa0fdf8c333955de80167972bf83b22c6564c0 Mon Sep 17 00:00:00 2001 From: Matt Valentine-House Date: Mon, 24 Jan 2022 16:05:23 +0000 Subject: [PATCH] [wip] Allow callbacks to be registered for GVL related events --- .../gvl/call_without_gvl/call_without_gvl.c | 22 +++++++++++++ include/ruby/thread.h | 1 + include/ruby/thread_native.h | 7 +++++ test/-ext-/gvl/test_last_thread.rb | 7 +++++ thread_pthread.c | 31 +++++++++++++++++++ thread_pthread.h | 11 +++++++ 6 files changed, 79 insertions(+) diff --git a/ext/-test-/gvl/call_without_gvl/call_without_gvl.c b/ext/-test-/gvl/call_without_gvl/call_without_gvl.c index 233635421b816f..e845914782d8ae 100644 --- a/ext/-test-/gvl/call_without_gvl/call_without_gvl.c +++ b/ext/-test-/gvl/call_without_gvl/call_without_gvl.c @@ -1,5 +1,6 @@ #include "ruby/ruby.h" #include "ruby/thread.h" +#include "ruby/thread_native.h" static void* native_sleep_callback(void *data) @@ -68,6 +69,25 @@ thread_ubf_async_safe(VALUE thread, VALUE notify_fd) return Qnil; } +void +ex_callback(uint32_t e, struct gvl_hook_event_args args) { + fprintf(stderr, "calling callback\n"); +} + +static VALUE +thread_register_gvl_callback(VALUE thread) { + rb_gvl_event_new(*ex_callback, 0x12); + + + return Qnil; +} + +static VALUE +thread_call_gvl_callback(VALUE thread) { + rb_gvl_execute_hooks(0x12); + return Qnil; +} + void Init_call_without_gvl(void) { @@ -75,4 +95,6 @@ Init_call_without_gvl(void) VALUE klass = rb_define_module_under(mBug, "Thread"); rb_define_singleton_method(klass, "runnable_sleep", thread_runnable_sleep, 1); rb_define_singleton_method(klass, "ubf_async_safe", thread_ubf_async_safe, 1); + rb_define_singleton_method(klass, "register_callback", thread_register_gvl_callback, 0); + rb_define_singleton_method(klass, "call_callbacks", thread_call_gvl_callback, 0); } diff --git a/include/ruby/thread.h b/include/ruby/thread.h index 18c792b3861ccc..cc0ceeffc4cc09 100644 --- a/include/ruby/thread.h +++ b/include/ruby/thread.h @@ -190,6 +190,7 @@ void *rb_nogvl(void *(*func)(void *), void *data1, */ #define RUBY_CALL_WO_GVL_FLAG_SKIP_CHECK_INTS_ + RBIMPL_SYMBOL_EXPORT_END() #endif /* RUBY_THREAD_H */ diff --git a/include/ruby/thread_native.h b/include/ruby/thread_native.h index c23b15e133a81f..ae1df02343f7ee 100644 --- a/include/ruby/thread_native.h +++ b/include/ruby/thread_native.h @@ -201,5 +201,12 @@ void rb_native_cond_initialize(rb_nativethread_cond_t *cond); */ void rb_native_cond_destroy(rb_nativethread_cond_t *cond); +#include +struct gvl_hook_event_args { + // +}; +typedef void (*rb_gvl_callback)(uint32_t event, struct gvl_hook_event_args args); +void rb_gvl_event_new(void *callback, uint32_t event); +void rb_gvl_execute_hooks(uint32_t event); RBIMPL_SYMBOL_EXPORT_END() #endif diff --git a/test/-ext-/gvl/test_last_thread.rb b/test/-ext-/gvl/test_last_thread.rb index f1bebafeea942e..791e13834d581a 100644 --- a/test/-ext-/gvl/test_last_thread.rb +++ b/test/-ext-/gvl/test_last_thread.rb @@ -18,5 +18,12 @@ def test_last_thread assert_in_delta(1.0, t, 0.16) end; end + + def test_gvl_instrumentation + require '-test-/gvl/call_without_gvl' + Bug::Thread::register_callback + + Bug::Thread::call_callbacks + end end diff --git a/thread_pthread.c b/thread_pthread.c index 55289de73a3be4..5665afbe727679 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -101,6 +101,37 @@ # endif #endif +static gvl_hook_t * rb_gvl_hooks = NULL; + +void +rb_gvl_event_new(void *callback, uint32_t event) { + gvl_hook_t *hook = ALLOC_N(gvl_hook_t, 1); + hook->callback = callback; + hook->event = event; + + if(!rb_gvl_hooks) { + rb_gvl_hooks = hook; + } else { + hook->next = rb_gvl_hooks; + rb_gvl_hooks = hook; + } +} + +void +rb_gvl_execute_hooks(uint32_t event) { + if (!rb_gvl_hooks) { + return; + } + gvl_hook_t *h = rb_gvl_hooks; + struct gvl_hook_event_args args = {}; + + do { + if (h->event & event) { + (*h->callback)(event, args); + } + } while((h = h->next)); +} + enum rtimer_state { /* alive, after timer_create: */ RTIMER_DISARM, diff --git a/thread_pthread.h b/thread_pthread.h index 2ac354046c010b..240c8d9fe453e6 100644 --- a/thread_pthread.h +++ b/thread_pthread.h @@ -69,6 +69,17 @@ typedef struct rb_global_vm_lock_struct { int wait_yield; } rb_global_vm_lock_t; +#include + +// TODO: this is going to be the same on Windows so move it somewhere sensible +typedef struct gvl_hook { + rb_gvl_callback callback; + uint32_t event; + + struct gvl_hook *next; +} gvl_hook_t; + +#include "ruby/internal/memory.h" #if __STDC_VERSION__ >= 201112 #define RB_THREAD_LOCAL_SPECIFIER _Thread_local