Skip to content

Commit c3fa0fd

Browse files
[wip] Allow callbacks to be registered for GVL related events
1 parent 374904b commit c3fa0fd

File tree

6 files changed

+79
-0
lines changed

6 files changed

+79
-0
lines changed

ext/-test-/gvl/call_without_gvl/call_without_gvl.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "ruby/ruby.h"
22
#include "ruby/thread.h"
3+
#include "ruby/thread_native.h"
34

45
static void*
56
native_sleep_callback(void *data)
@@ -68,11 +69,32 @@ thread_ubf_async_safe(VALUE thread, VALUE notify_fd)
6869
return Qnil;
6970
}
7071

72+
void
73+
ex_callback(uint32_t e, struct gvl_hook_event_args args) {
74+
fprintf(stderr, "calling callback\n");
75+
}
76+
77+
static VALUE
78+
thread_register_gvl_callback(VALUE thread) {
79+
rb_gvl_event_new(*ex_callback, 0x12);
80+
81+
82+
return Qnil;
83+
}
84+
85+
static VALUE
86+
thread_call_gvl_callback(VALUE thread) {
87+
rb_gvl_execute_hooks(0x12);
88+
return Qnil;
89+
}
90+
7191
void
7292
Init_call_without_gvl(void)
7393
{
7494
VALUE mBug = rb_define_module("Bug");
7595
VALUE klass = rb_define_module_under(mBug, "Thread");
7696
rb_define_singleton_method(klass, "runnable_sleep", thread_runnable_sleep, 1);
7797
rb_define_singleton_method(klass, "ubf_async_safe", thread_ubf_async_safe, 1);
98+
rb_define_singleton_method(klass, "register_callback", thread_register_gvl_callback, 0);
99+
rb_define_singleton_method(klass, "call_callbacks", thread_call_gvl_callback, 0);
78100
}

include/ruby/thread.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ void *rb_nogvl(void *(*func)(void *), void *data1,
190190
*/
191191
#define RUBY_CALL_WO_GVL_FLAG_SKIP_CHECK_INTS_
192192

193+
193194
RBIMPL_SYMBOL_EXPORT_END()
194195

195196
#endif /* RUBY_THREAD_H */

include/ruby/thread_native.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,5 +201,12 @@ void rb_native_cond_initialize(rb_nativethread_cond_t *cond);
201201
*/
202202
void rb_native_cond_destroy(rb_nativethread_cond_t *cond);
203203

204+
#include <stdint.h>
205+
struct gvl_hook_event_args {
206+
//
207+
};
208+
typedef void (*rb_gvl_callback)(uint32_t event, struct gvl_hook_event_args args);
209+
void rb_gvl_event_new(void *callback, uint32_t event);
210+
void rb_gvl_execute_hooks(uint32_t event);
204211
RBIMPL_SYMBOL_EXPORT_END()
205212
#endif

test/-ext-/gvl/test_last_thread.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,12 @@ def test_last_thread
1818
assert_in_delta(1.0, t, 0.16)
1919
end;
2020
end
21+
22+
def test_gvl_instrumentation
23+
require '-test-/gvl/call_without_gvl'
24+
Bug::Thread::register_callback
25+
26+
Bug::Thread::call_callbacks
27+
end
2128
end
2229

thread_pthread.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,37 @@
101101
# endif
102102
#endif
103103

104+
static gvl_hook_t * rb_gvl_hooks = NULL;
105+
106+
void
107+
rb_gvl_event_new(void *callback, uint32_t event) {
108+
gvl_hook_t *hook = ALLOC_N(gvl_hook_t, 1);
109+
hook->callback = callback;
110+
hook->event = event;
111+
112+
if(!rb_gvl_hooks) {
113+
rb_gvl_hooks = hook;
114+
} else {
115+
hook->next = rb_gvl_hooks;
116+
rb_gvl_hooks = hook;
117+
}
118+
}
119+
120+
void
121+
rb_gvl_execute_hooks(uint32_t event) {
122+
if (!rb_gvl_hooks) {
123+
return;
124+
}
125+
gvl_hook_t *h = rb_gvl_hooks;
126+
struct gvl_hook_event_args args = {};
127+
128+
do {
129+
if (h->event & event) {
130+
(*h->callback)(event, args);
131+
}
132+
} while((h = h->next));
133+
}
134+
104135
enum rtimer_state {
105136
/* alive, after timer_create: */
106137
RTIMER_DISARM,

thread_pthread.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,17 @@ typedef struct rb_global_vm_lock_struct {
6969
int wait_yield;
7070
} rb_global_vm_lock_t;
7171

72+
#include <stdint.h>
73+
74+
// TODO: this is going to be the same on Windows so move it somewhere sensible
75+
typedef struct gvl_hook {
76+
rb_gvl_callback callback;
77+
uint32_t event;
78+
79+
struct gvl_hook *next;
80+
} gvl_hook_t;
81+
82+
#include "ruby/internal/memory.h"
7283

7384
#if __STDC_VERSION__ >= 201112
7485
#define RB_THREAD_LOCAL_SPECIFIER _Thread_local

0 commit comments

Comments
 (0)