Skip to content

Commit

Permalink
Basic unregister GVL callbacks API (thread unsafe)
Browse files Browse the repository at this point in the history
  • Loading branch information
byroot committed Jan 25, 2022
1 parent c3fa0fd commit e0c541b
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 16 deletions.
32 changes: 30 additions & 2 deletions ext/-test-/gvl/call_without_gvl/call_without_gvl.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,20 +74,46 @@ ex_callback(uint32_t e, struct gvl_hook_event_args args) {
fprintf(stderr, "calling callback\n");
}

static gvl_hook_t * single_hook = NULL;

static VALUE
thread_register_gvl_callback(VALUE thread) {
rb_gvl_event_new(*ex_callback, 0x12);
single_hook = rb_gvl_event_new(*ex_callback, 0x12);

return Qnil;
}

static VALUE
thread_unregister_gvl_callback(VALUE thread) {
if (single_hook) {
rb_gvl_event_delete(single_hook);
single_hook = NULL;
}

return Qnil;
}

static VALUE
thread_call_gvl_callback(VALUE thread) {
rb_gvl_execute_hooks(0x12);
rb_gvl_execute_hooks(0x12);
return Qnil;
}

static VALUE
thread_register_and_unregister_gvl_callback(VALUE thread) {
gvl_hook_t * hooks[5];
for (int i = 0; i < 5; i++) {
hooks[i] = rb_gvl_event_new(*ex_callback, 0x12);
}

if (!rb_gvl_event_delete(hooks[4])) return Qfalse;
if (!rb_gvl_event_delete(hooks[0])) return Qfalse;
if (!rb_gvl_event_delete(hooks[3])) return Qfalse;
if (!rb_gvl_event_delete(hooks[2])) return Qfalse;
if (!rb_gvl_event_delete(hooks[1])) return Qfalse;
return Qtrue;
}

void
Init_call_without_gvl(void)
{
Expand All @@ -96,5 +122,7 @@ Init_call_without_gvl(void)
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, "unregister_callback", thread_unregister_gvl_callback, 0);
rb_define_singleton_method(klass, "register_and_unregister_callbacks", thread_register_and_unregister_gvl_callback, 0);
rb_define_singleton_method(klass, "call_callbacks", thread_call_gvl_callback, 0);
}
16 changes: 15 additions & 1 deletion include/ruby/thread_native.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,22 @@ void rb_native_cond_destroy(rb_nativethread_cond_t *cond);
struct gvl_hook_event_args {
//
};
#include <stdint.h>

typedef void (*rb_gvl_callback)(uint32_t event, struct gvl_hook_event_args args);
void rb_gvl_event_new(void *callback, uint32_t event);

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

gvl_hook_t * rb_gvl_event_new(void *callback, uint32_t event);
bool rb_gvl_event_delete(gvl_hook_t * hook);
void rb_gvl_execute_hooks(uint32_t event);
RBIMPL_SYMBOL_EXPORT_END()
#endif
11 changes: 10 additions & 1 deletion test/-ext-/gvl/test_last_thread.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,16 @@ def test_gvl_instrumentation
require '-test-/gvl/call_without_gvl'
Bug::Thread::register_callback

Bug::Thread::call_callbacks
begin
Bug::Thread::call_callbacks
ensure
Bug::Thread::unregister_callback
end
end

def test_gvl_instrumentation_unregister
require '-test-/gvl/call_without_gvl'
assert Bug::Thread::register_and_unregister_callbacks
end
end

24 changes: 23 additions & 1 deletion thread_pthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@

static gvl_hook_t * rb_gvl_hooks = NULL;

void
gvl_hook_t *
rb_gvl_event_new(void *callback, uint32_t event) {
gvl_hook_t *hook = ALLOC_N(gvl_hook_t, 1);
hook->callback = callback;
Expand All @@ -115,6 +115,28 @@ rb_gvl_event_new(void *callback, uint32_t event) {
hook->next = rb_gvl_hooks;
rb_gvl_hooks = hook;
}
return hook;
}

bool
rb_gvl_event_delete(gvl_hook_t * hook) {
if (rb_gvl_hooks == hook) {
rb_gvl_hooks = hook->next;
ruby_xfree(hook);
return TRUE;
}

gvl_hook_t *h = rb_gvl_hooks;

do {
if (h->next == hook) {
h->next = hook->next;
ruby_xfree(hook);
return TRUE;
}
} while ((h = h->next));

return FALSE;
}

void
Expand Down
11 changes: 0 additions & 11 deletions thread_pthread.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,6 @@ 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
Expand Down

0 comments on commit e0c541b

Please sign in to comment.