Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wip] Allow callbacks to be registered for GVL related events #119

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
Next Next commit
[wip] Allow callbacks to be registered for GVL related events
  • Loading branch information
eightbitraptor committed Jan 24, 2022
commit c3fa0fdf8c333955de80167972bf83b22c6564c0
22 changes: 22 additions & 0 deletions ext/-test-/gvl/call_without_gvl/call_without_gvl.c
Original file line number Diff line number Diff line change
@@ -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,11 +69,32 @@ 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)
{
VALUE mBug = rb_define_module("Bug");
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);
}
1 change: 1 addition & 0 deletions include/ruby/thread.h
Original file line number Diff line number Diff line change
@@ -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 */
7 changes: 7 additions & 0 deletions include/ruby/thread_native.h
Original file line number Diff line number Diff line change
@@ -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 <stdint.h>
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
7 changes: 7 additions & 0 deletions test/-ext-/gvl/test_last_thread.rb
Original file line number Diff line number Diff line change
@@ -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

31 changes: 31 additions & 0 deletions thread_pthread.c
Original file line number Diff line number Diff line change
@@ -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,
11 changes: 11 additions & 0 deletions thread_pthread.h
Original file line number Diff line number Diff line change
@@ -69,6 +69,17 @@ typedef struct rb_global_vm_lock_struct {
int wait_yield;
} rb_global_vm_lock_t;

#include <stdint.h>

// 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