Skip to content

Commit 4d48cfe

Browse files
committed
Make rb_gvl hook API thread safe
1 parent e0c541b commit 4d48cfe

File tree

1 file changed

+43
-18
lines changed

1 file changed

+43
-18
lines changed

thread_pthread.c

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -102,48 +102,69 @@
102102
#endif
103103

104104
static gvl_hook_t * rb_gvl_hooks = NULL;
105+
static pthread_rwlock_t rb_gvl_hooks_rw_lock = PTHREAD_RWLOCK_INITIALIZER;
105106

106107
gvl_hook_t *
107108
rb_gvl_event_new(void *callback, uint32_t event) {
108109
gvl_hook_t *hook = ALLOC_N(gvl_hook_t, 1);
109110
hook->callback = callback;
110111
hook->event = event;
111112

112-
if(!rb_gvl_hooks) {
113-
rb_gvl_hooks = hook;
114-
} else {
115-
hook->next = rb_gvl_hooks;
116-
rb_gvl_hooks = hook;
113+
if (pthread_rwlock_wrlock(&rb_gvl_hooks_rw_lock)) {
114+
// TODO: better way to deal with error?
115+
ruby_xfree(hook);
116+
return NULL;
117117
}
118+
119+
hook->next = rb_gvl_hooks;
120+
ATOMIC_PTR_EXCHANGE(rb_gvl_hooks, hook);
121+
122+
pthread_rwlock_unlock(&rb_gvl_hooks_rw_lock);
118123
return hook;
119124
}
120125

121126
bool
122127
rb_gvl_event_delete(gvl_hook_t * hook) {
128+
if (pthread_rwlock_wrlock(&rb_gvl_hooks_rw_lock)) {
129+
// TODO: better way to deal with error?
130+
return FALSE;
131+
}
132+
133+
bool success = FALSE;
134+
123135
if (rb_gvl_hooks == hook) {
124-
rb_gvl_hooks = hook->next;
125-
ruby_xfree(hook);
126-
return TRUE;
136+
ATOMIC_PTR_EXCHANGE(rb_gvl_hooks, hook->next);
137+
success = TRUE;
138+
} else {
139+
gvl_hook_t *h = rb_gvl_hooks;
140+
141+
do {
142+
if (h->next == hook) {
143+
h->next = hook->next;
144+
success = TRUE;
145+
}
146+
} while ((h = h->next));
127147
}
128-
129-
gvl_hook_t *h = rb_gvl_hooks;
130148

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));
149+
pthread_rwlock_unlock(&rb_gvl_hooks_rw_lock);
138150

139-
return FALSE;
151+
if (success) {
152+
ruby_xfree(hook);
153+
}
154+
return success;
140155
}
141156

142157
void
143158
rb_gvl_execute_hooks(uint32_t event) {
144159
if (!rb_gvl_hooks) {
145160
return;
146161
}
162+
163+
if (pthread_rwlock_rdlock(&rb_gvl_hooks_rw_lock)) {
164+
// TODO: better way to deal with error?
165+
return;
166+
}
167+
147168
gvl_hook_t *h = rb_gvl_hooks;
148169
struct gvl_hook_event_args args = {};
149170

@@ -152,6 +173,8 @@ rb_gvl_execute_hooks(uint32_t event) {
152173
(*h->callback)(event, args);
153174
}
154175
} while((h = h->next));
176+
177+
pthread_rwlock_unlock(&rb_gvl_hooks_rw_lock);
155178
}
156179

157180
enum rtimer_state {
@@ -697,6 +720,8 @@ static void native_thread_init(rb_thread_t *th);
697720
void
698721
Init_native_thread(rb_thread_t *th)
699722
{
723+
pthread_rwlock_init(&rb_gvl_hooks_rw_lock, NULL);
724+
700725
#if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK)
701726
if (condattr_monotonic) {
702727
int r = pthread_condattr_init(condattr_monotonic);

0 commit comments

Comments
 (0)