Skip to content

Commit b01459b

Browse files
committedJan 25, 2022
Basic unregister GVL callbacks API (thread unsafe)
1 parent c3fa0fd commit b01459b

File tree

5 files changed

+78
-15
lines changed

5 files changed

+78
-15
lines changed
 

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

+30-1
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,21 @@ ex_callback(uint32_t e, struct gvl_hook_event_args args) {
7474
fprintf(stderr, "calling callback\n");
7575
}
7676

77+
static gvl_hook_t * single_hook = NULL;
78+
7779
static VALUE
7880
thread_register_gvl_callback(VALUE thread) {
79-
rb_gvl_event_new(*ex_callback, 0x12);
81+
single_hook = rb_gvl_event_new(*ex_callback, 0x12);
82+
83+
return Qnil;
84+
}
8085

86+
static VALUE
87+
thread_unregister_gvl_callback(VALUE thread) {
88+
if (single_hook) {
89+
rb_gvl_event_delete(single_hook);
90+
single_hook = NULL;
91+
}
8192

8293
return Qnil;
8394
}
@@ -88,6 +99,21 @@ thread_call_gvl_callback(VALUE thread) {
8899
return Qnil;
89100
}
90101

102+
static VALUE
103+
thread_register_and_unregister_gvl_callback(VALUE thread) {
104+
gvl_hook_t * hooks[5];
105+
for (int i = 0; i < 5; i++) {
106+
hooks[i] = rb_gvl_event_new(*ex_callback, 0x12);
107+
}
108+
109+
if (!rb_gvl_event_delete(hooks[4])) return Qfalse;
110+
if (!rb_gvl_event_delete(hooks[0])) return Qfalse;
111+
if (!rb_gvl_event_delete(hooks[3])) return Qfalse;
112+
if (!rb_gvl_event_delete(hooks[2])) return Qfalse;
113+
if (!rb_gvl_event_delete(hooks[1])) return Qfalse;
114+
return Qtrue;
115+
}
116+
91117
void
92118
Init_call_without_gvl(void)
93119
{
@@ -96,5 +122,8 @@ Init_call_without_gvl(void)
96122
rb_define_singleton_method(klass, "runnable_sleep", thread_runnable_sleep, 1);
97123
rb_define_singleton_method(klass, "ubf_async_safe", thread_ubf_async_safe, 1);
98124
rb_define_singleton_method(klass, "register_callback", thread_register_gvl_callback, 0);
125+
rb_define_singleton_method(klass, "unregister_callback", thread_unregister_gvl_callback, 0);
126+
rb_define_singleton_method(klass, "register_and_unregister_callbacks", thread_register_and_unregister_gvl_callback, 0);
99127
rb_define_singleton_method(klass, "call_callbacks", thread_call_gvl_callback, 0);
128+
100129
}

‎include/ruby/thread_native.h

+15-1
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,22 @@ void rb_native_cond_destroy(rb_nativethread_cond_t *cond);
205205
struct gvl_hook_event_args {
206206
//
207207
};
208+
#include <stdint.h>
209+
208210
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);
211+
212+
// TODO: this is going to be the same on Windows so move it somewhere sensible
213+
typedef struct gvl_hook {
214+
rb_gvl_callback callback;
215+
uint32_t event;
216+
217+
struct gvl_hook *next;
218+
} gvl_hook_t;
219+
220+
#include "ruby/internal/memory.h"
221+
222+
gvl_hook_t * rb_gvl_event_new(void *callback, uint32_t event);
223+
bool rb_gvl_event_delete(gvl_hook_t * hook);
210224
void rb_gvl_execute_hooks(uint32_t event);
211225
RBIMPL_SYMBOL_EXPORT_END()
212226
#endif

‎test/-ext-/gvl/test_last_thread.rb

+10-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,16 @@ def test_gvl_instrumentation
2323
require '-test-/gvl/call_without_gvl'
2424
Bug::Thread::register_callback
2525

26-
Bug::Thread::call_callbacks
26+
begin
27+
Bug::Thread::call_callbacks
28+
ensure
29+
Bug::Thread::unregister_callback
30+
end
31+
end
32+
33+
def test_gvl_instrumentation_unregister
34+
require '-test-/gvl/call_without_gvl'
35+
assert Bug::Thread::register_and_unregister_callbacks
2736
end
2837
end
2938

‎thread_pthread.c

+23-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@
103103

104104
static gvl_hook_t * rb_gvl_hooks = NULL;
105105

106-
void
106+
gvl_hook_t *
107107
rb_gvl_event_new(void *callback, uint32_t event) {
108108
gvl_hook_t *hook = ALLOC_N(gvl_hook_t, 1);
109109
hook->callback = callback;
@@ -115,6 +115,28 @@ rb_gvl_event_new(void *callback, uint32_t event) {
115115
hook->next = rb_gvl_hooks;
116116
rb_gvl_hooks = hook;
117117
}
118+
return hook;
119+
}
120+
121+
bool
122+
rb_gvl_event_delete(gvl_hook_t * hook) {
123+
if (rb_gvl_hooks == hook) {
124+
rb_gvl_hooks = hook->next;
125+
ruby_xfree(hook);
126+
return TRUE;
127+
}
128+
129+
gvl_hook_t *h = rb_gvl_hooks;
130+
131+
do {
132+
if (h->next == hook) {
133+
h->next = hook->next;
134+
ruby_xfree(hook);
135+
return TRUE;
136+
}
137+
} while ((h = h->next));
138+
139+
return FALSE;
118140
}
119141

120142
void

‎thread_pthread.h

-11
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,6 @@ 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"
8372

8473
#if __STDC_VERSION__ >= 201112
8574
#define RB_THREAD_LOCAL_SPECIFIER _Thread_local

0 commit comments

Comments
 (0)
Failed to load comments.