21
21
struct em_proxying_queue {
22
22
// Protects all accesses to em_task_queues, size, and capacity.
23
23
pthread_mutex_t mutex ;
24
- // If the mutex is locked this is the thread that is using it.
25
- pthread_t active_thread ;
26
24
// `size` task queue pointers stored in an array of size `capacity`.
27
25
em_task_queue * * task_queues ;
28
26
int size ;
@@ -32,12 +30,13 @@ struct em_proxying_queue {
32
30
// The system proxying queue.
33
31
static em_proxying_queue system_proxying_queue = {
34
32
.mutex = PTHREAD_MUTEX_INITIALIZER ,
35
- .active_thread = NULL ,
36
33
.task_queues = NULL ,
37
34
.size = 0 ,
38
35
.capacity = 0 ,
39
36
};
40
37
38
+ static _Thread_local int system_queue_in_use = 0 ;
39
+
41
40
em_proxying_queue * emscripten_proxy_get_system_queue (void ) {
42
41
return & system_proxying_queue ;
43
42
}
@@ -50,7 +49,6 @@ em_proxying_queue* em_proxying_queue_create(void) {
50
49
}
51
50
* q = (em_proxying_queue ){
52
51
.mutex = PTHREAD_MUTEX_INITIALIZER ,
53
- .active_thread = NULL ,
54
52
.task_queues = NULL ,
55
53
.size = 0 ,
56
54
.capacity = 0 ,
@@ -110,32 +108,28 @@ static em_task_queue* get_or_add_tasks_for_thread(em_proxying_queue* q,
110
108
return tasks ;
111
109
}
112
110
113
- static _Thread_local bool executing_system_queue = false;
114
-
115
111
void emscripten_proxy_execute_queue (em_proxying_queue * q ) {
116
112
assert (q != NULL );
117
113
assert (pthread_self ());
118
114
119
- // Recursion guard to avoid infinite recursion when we arrive here from the
120
- // pthread_lock call below that executes the system queue. The per-task_queue
121
- // recursion lock can't catch these recursions because it can only be checked
122
- // after the lock has been acquired.
123
- bool is_system_queue = q == & system_proxying_queue ;
124
- if (is_system_queue ) {
125
- if (executing_system_queue ) {
126
- return ;
127
- }
128
- executing_system_queue = true;
129
- }
130
-
131
- // When the current thread is adding tasks it locks the queue, but we can
115
+ // Below is a recursion and deadlock guard:
116
+ // The recursion guard is to avoid infinite recursion when we arrive here from
117
+ // the pthread_lock call below that executes the system queue. The
118
+ // per-task_queue recursion lock can't catch these recursions because it can
119
+ // only be checked after the lock has been acquired.
120
+ //
121
+ // This also guards against deadlocks when adding to the system queue. When
122
+ // the current thread is adding tasks, it locks the queue, but we can
132
123
// potentially try to execute the queue during the add (from
133
124
// emscripten_yield). This will deadlock the thread, so only try to take the
134
- // lock if the current thread is not adding to the queue. We then hope the
125
+ // lock if the current thread is not using the queue. We then hope the
135
126
// queue is executed later when it is unlocked.
136
- // XXX: This could leave to starvation if we never process the queue.
137
- if (q -> active_thread == pthread_self ()) {
138
- return ;
127
+ int is_system_queue = q == & system_proxying_queue ;
128
+ if (is_system_queue ) {
129
+ if (system_queue_in_use ) {
130
+ return ;
131
+ }
132
+ system_queue_in_use = true;
139
133
}
140
134
141
135
pthread_mutex_lock (& q -> mutex );
@@ -148,16 +142,21 @@ void emscripten_proxy_execute_queue(em_proxying_queue* q) {
148
142
}
149
143
150
144
if (is_system_queue ) {
151
- executing_system_queue = false;
145
+ system_queue_in_use = false;
152
146
}
153
147
}
154
148
155
149
static int do_proxy (em_proxying_queue * q , pthread_t target_thread , task t ) {
156
150
assert (q != NULL );
157
151
pthread_mutex_lock (& q -> mutex );
158
- q -> active_thread = pthread_self ();
152
+ int is_system_queue = q == & system_proxying_queue ;
153
+ if (is_system_queue ) {
154
+ system_queue_in_use = 1 ;
155
+ }
159
156
em_task_queue * tasks = get_or_add_tasks_for_thread (q , target_thread );
160
- q -> active_thread = NULL ;
157
+ if (is_system_queue ) {
158
+ system_queue_in_use = 0 ;
159
+ }
161
160
pthread_mutex_unlock (& q -> mutex );
162
161
if (tasks == NULL ) {
163
162
return 0 ;
0 commit comments