| 109 | } |
| 110 | |
| 111 | void emscripten_proxy_execute_queue(em_proxying_queue* q) { |
| 112 | assert(q != NULL); |
| 113 | assert(pthread_self()); |
| 114 | |
| 115 | // Below is a recursion and deadlock guard: The recursion guard is to avoid |
| 116 | // infinite recursion when we arrive here from the pthread_lock call below |
| 117 | // that executes the system queue. The per-task_queue recursion lock can't |
| 118 | // catch these recursions because it can only be checked after the lock has |
| 119 | // 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 |
| 123 | // potentially try to execute the queue during the add (from emscripten_yield |
| 124 | // when malloc takes a lock). This will deadlock the thread, so only try to |
| 125 | // take the lock if the current thread is not using the queue. We then hope |
| 126 | // the queue is executed later when it is unlocked. |
| 127 | bool 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; |
| 133 | } |
| 134 | |
| 135 | pthread_mutex_lock(&q->mutex); |
| 136 | em_task_queue* tasks = get_tasks_for_thread(q, pthread_self()); |
| 137 | pthread_mutex_unlock(&q->mutex); |
| 138 | |
| 139 | if (tasks != NULL && !tasks->processing) { |
| 140 | // Found the task queue and it is not already being processed; process it. |
| 141 | em_task_queue_execute(tasks); |
| 142 | } |
| 143 | |
| 144 | if (is_system_queue) { |
| 145 | system_queue_in_use = false; |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | static bool do_proxy(em_proxying_queue* q, pthread_t target_thread, task t) { |
| 150 | assert(q != NULL); |