102
102
#endif
103
103
104
104
static gvl_hook_t * rb_gvl_hooks = NULL ;
105
+ static pthread_rwlock_t rb_gvl_hooks_rw_lock = PTHREAD_RWLOCK_INITIALIZER ;
105
106
106
107
gvl_hook_t *
107
108
rb_gvl_event_new (void * callback , uint32_t event ) {
108
109
gvl_hook_t * hook = ALLOC_N (gvl_hook_t , 1 );
109
110
hook -> callback = callback ;
110
111
hook -> event = event ;
111
112
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 ;
117
117
}
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 );
118
123
return hook ;
119
124
}
120
125
121
126
bool
122
127
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
+
123
135
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 ));
127
147
}
128
-
129
- gvl_hook_t * h = rb_gvl_hooks ;
130
148
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 );
138
150
139
- return FALSE;
151
+ if (success ) {
152
+ ruby_xfree (hook );
153
+ }
154
+ return success ;
140
155
}
141
156
142
157
void
143
158
rb_gvl_execute_hooks (uint32_t event ) {
144
159
if (!rb_gvl_hooks ) {
145
160
return ;
146
161
}
162
+
163
+ if (pthread_rwlock_rdlock (& rb_gvl_hooks_rw_lock )) {
164
+ // TODO: better way to deal with error?
165
+ return ;
166
+ }
167
+
147
168
gvl_hook_t * h = rb_gvl_hooks ;
148
169
struct gvl_hook_event_args args = {};
149
170
@@ -152,6 +173,8 @@ rb_gvl_execute_hooks(uint32_t event) {
152
173
(* h -> callback )(event , args );
153
174
}
154
175
} while ((h = h -> next ));
176
+
177
+ pthread_rwlock_unlock (& rb_gvl_hooks_rw_lock );
155
178
}
156
179
157
180
enum rtimer_state {
@@ -697,6 +720,8 @@ static void native_thread_init(rb_thread_t *th);
697
720
void
698
721
Init_native_thread (rb_thread_t * th )
699
722
{
723
+ pthread_rwlock_init (& rb_gvl_hooks_rw_lock , NULL );
724
+
700
725
#if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK )
701
726
if (condattr_monotonic ) {
702
727
int r = pthread_condattr_init (condattr_monotonic );
0 commit comments