102102#endif
103103
104104static gvl_hook_t * rb_gvl_hooks = NULL ;
105+ static pthread_rwlock_t rb_gvl_hooks_rw_lock = PTHREAD_RWLOCK_INITIALIZER ;
105106
106107gvl_hook_t *
107108rb_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
121126bool
122127rb_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
142157void
143158rb_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
157180enum rtimer_state {
@@ -697,6 +720,8 @@ static void native_thread_init(rb_thread_t *th);
697720void
698721Init_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