1 /*
2  * Copyright 2015 The Emscripten Authors.  All rights reserved.
3  * Emscripten is available under two separate licenses, the MIT license and the
4  * University of Illinois/NCSA Open Source License.  Both these licenses can be
5  * found in the LICENSE file.
6  */
7 
8 #define _GNU_SOURCE
9 #include "../internal/libc.h"
10 #include "../internal/pthread_impl.h"
11 #include <assert.h>
12 #include <dirent.h>
13 #include <emscripten.h>
14 #include <emscripten/threading.h>
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <math.h>
18 #include <poll.h>
19 #include <pthread.h>
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/ioctl.h>
24 #include <sys/mman.h>
25 #include <sys/socket.h>
26 #include <sys/stat.h>
27 #include <sys/statvfs.h>
28 #include <sys/time.h>
29 #include <termios.h>
30 #include <unistd.h>
31 #include <utime.h>
32 
33 // With LLVM 3.6, C11 is the default compilation mode.
34 // gets() is deprecated under that standard, but emcc
35 // still provides it, so always include it in the build.
36 #if __STDC_VERSION__ >= 201112L
37 char* gets(char*);
38 #endif
39 
40 // Extra pthread_attr_t field:
41 #define _a_transferredcanvases __u.__s[9]
42 
43 void __pthread_testcancel();
44 
emscripten_pthread_attr_gettransferredcanvases(const pthread_attr_t * a,const char ** str)45 int emscripten_pthread_attr_gettransferredcanvases(const pthread_attr_t* a, const char** str) {
46   *str = (const char*)a->_a_transferredcanvases;
47   return 0;
48 }
49 
emscripten_pthread_attr_settransferredcanvases(pthread_attr_t * a,const char * str)50 int emscripten_pthread_attr_settransferredcanvases(pthread_attr_t* a, const char* str) {
51   a->_a_transferredcanvases = (int)str;
52   return 0;
53 }
54 
_pthread_getcanceltype()55 int _pthread_getcanceltype() { return pthread_self()->cancelasync; }
56 
__pthread_mutex_locked(pthread_mutex_t * mutex)57 static void inline __pthread_mutex_locked(pthread_mutex_t* mutex) {
58   // The lock is now ours, mark this thread as the owner of this lock.
59   assert(mutex);
60   assert(mutex->_m_lock == 0);
61   mutex->_m_lock = pthread_self()->tid;
62   if (_pthread_getcanceltype() == PTHREAD_CANCEL_ASYNCHRONOUS)
63     __pthread_testcancel();
64 }
65 
sched_get_priority_max(int policy)66 int sched_get_priority_max(int policy) {
67   // Web workers do not actually support prioritizing threads,
68   // but mimic values that Linux apparently reports, see
69   // http://man7.org/linux/man-pages/man2/sched_get_priority_min.2.html
70   if (policy == SCHED_FIFO || policy == SCHED_RR)
71     return 99;
72   else
73     return 0;
74 }
75 
sched_get_priority_min(int policy)76 int sched_get_priority_min(int policy) {
77   // Web workers do not actually support prioritizing threads,
78   // but mimic values that Linux apparently reports, see
79   // http://man7.org/linux/man-pages/man2/sched_get_priority_min.2.html
80   if (policy == SCHED_FIFO || policy == SCHED_RR)
81     return 1;
82   else
83     return 0;
84 }
85 
pthread_setcancelstate(int new,int * old)86 int pthread_setcancelstate(int new, int* old) {
87   if (new > 1U)
88     return EINVAL;
89   struct pthread* self = pthread_self();
90   if (old)
91     *old = self->canceldisable;
92   self->canceldisable = new;
93   return 0;
94 }
95 
_pthread_isduecanceled(struct pthread * pthread_ptr)96 int _pthread_isduecanceled(struct pthread* pthread_ptr) {
97   return pthread_ptr->threadStatus == 2 /*canceled*/;
98 }
99 
__pthread_testcancel()100 void __pthread_testcancel() {
101   struct pthread* self = pthread_self();
102   if (self->canceldisable)
103     return;
104   if (_pthread_isduecanceled(self)) {
105     EM_ASM(throw 'Canceled!');
106   }
107 }
108 
pthread_getattr_np(pthread_t t,pthread_attr_t * a)109 int pthread_getattr_np(pthread_t t, pthread_attr_t* a) {
110   *a = (pthread_attr_t){0};
111   a->_a_detach = !!t->detached;
112   a->_a_stackaddr = (uintptr_t)t->stack;
113   a->_a_stacksize = t->stack_size - DEFAULT_STACK_SIZE;
114   return 0;
115 }
116 
117 static uint32_t dummyZeroAddress = 0;
118 
emscripten_thread_sleep(double msecs)119 void emscripten_thread_sleep(double msecs) {
120   double now = emscripten_get_now();
121   double target = now + msecs;
122 
123   __pthread_testcancel(); // pthreads spec: sleep is a cancellation point, so must test if this
124                           // thread is cancelled during the sleep.
125   emscripten_current_thread_process_queued_calls();
126 
127   // If we have less than this many msecs left to wait, busy spin that instead.
128   const double minimumTimeSliceToSleep = 0.1;
129 
130   // main thread may need to run proxied calls, so sleep in very small slices to be responsive.
131   const double maxMsecsSliceToSleep = emscripten_is_main_browser_thread() ? 1 : 100;
132 
133   emscripten_conditional_set_current_thread_status(
134     EM_THREAD_STATUS_RUNNING, EM_THREAD_STATUS_SLEEPING);
135   now = emscripten_get_now();
136   while (now < target) {
137     // Keep processing the main loop of the calling thread.
138     __pthread_testcancel(); // pthreads spec: sleep is a cancellation point, so must test if this
139                             // thread is cancelled during the sleep.
140     emscripten_current_thread_process_queued_calls();
141 
142     now = emscripten_get_now();
143     double msecsToSleep = target - now;
144     if (msecsToSleep > maxMsecsSliceToSleep)
145       msecsToSleep = maxMsecsSliceToSleep;
146     if (msecsToSleep >= minimumTimeSliceToSleep)
147       emscripten_futex_wait(&dummyZeroAddress, 0, msecsToSleep);
148     now = emscripten_get_now();
149   };
150 
151   emscripten_conditional_set_current_thread_status(
152     EM_THREAD_STATUS_SLEEPING, EM_THREAD_STATUS_RUNNING);
153 }
154 
nanosleep(const struct timespec * req,struct timespec * rem)155 int nanosleep(const struct timespec* req, struct timespec* rem) {
156   if (!req || req->tv_nsec < 0 || req->tv_nsec > 999999999L || req->tv_sec < 0) {
157     errno = EINVAL;
158     return -1;
159   }
160   emscripten_thread_sleep(req->tv_sec * 1000.0 + req->tv_nsec / 1e6);
161   return 0;
162 }
163 
usleep(unsigned usec)164 int usleep(unsigned usec) {
165   emscripten_thread_sleep(usec / 1e3);
166   return 0;
167 }
168 
169 // Allocator and deallocator for em_queued_call objects.
em_queued_call_malloc()170 static em_queued_call* em_queued_call_malloc() {
171   em_queued_call* call = (em_queued_call*)malloc(sizeof(em_queued_call));
172   assert(call); // Not a programming error, but use assert() in debug builds to catch OOM scenarios.
173   if (call) {
174     call->operationDone = 0;
175     call->functionPtr = 0;
176     call->satelliteData = 0;
177   }
178   return call;
179 }
em_queued_call_free(em_queued_call * call)180 static void em_queued_call_free(em_queued_call* call) {
181   if (call)
182     free(call->satelliteData);
183   free(call);
184 }
185 
emscripten_async_waitable_close(em_queued_call * call)186 void emscripten_async_waitable_close(em_queued_call* call) { em_queued_call_free(call); }
187 
188 extern double emscripten_receive_on_main_thread_js(int functionIndex, int numCallArgs, double* args);
189 extern int _emscripten_notify_thread_queue(pthread_t targetThreadId, pthread_t mainThreadId);
190 
191 #if defined(__has_feature)
192 #if __has_feature(address_sanitizer)
193 #define HAS_ASAN
194 void __lsan_disable_in_this_thread(void);
195 void __lsan_enable_in_this_thread(void);
196 int emscripten_builtin_pthread_create(void *thread, void *attr,
197                                       void *(*callback)(void *), void *arg);
198 #endif
199 #endif
200 
_do_call(em_queued_call * q)201 static void _do_call(em_queued_call* q) {
202   // C function pointer
203   assert(EM_FUNC_SIG_NUM_FUNC_ARGUMENTS(q->functionEnum) <= EM_QUEUED_CALL_MAX_ARGS);
204   switch (q->functionEnum) {
205     case EM_PROXIED_PTHREAD_CREATE:
206 #ifdef HAS_ASAN
207       // ASan wraps the emscripten_builtin_pthread_create call in __lsan::ScopedInterceptorDisabler.
208       // Unfortunately, that only disables it on the thread that made the call.
209       // This is sufficient on the main thread.
210       // On non-main threads, pthread_create gets proxied to the main thread, where LSan is not
211       // disabled. This makes it necessary for us to disable LSan here, so that it does not detect
212       // pthread's internal allocations as leaks.
213       __lsan_disable_in_this_thread();
214       q->returnValue.i =
215         emscripten_builtin_pthread_create(q->args[0].vp, q->args[1].vp, q->args[2].vp, q->args[3].vp);
216       __lsan_enable_in_this_thread();
217 #else
218       q->returnValue.i =
219         pthread_create(q->args[0].vp, q->args[1].vp, q->args[2].vp, q->args[3].vp);
220 #endif
221       break;
222     case EM_PROXIED_CREATE_CONTEXT:
223       q->returnValue.i = emscripten_webgl_create_context(q->args[0].cp, q->args[1].vp);
224       break;
225     case EM_PROXIED_RESIZE_OFFSCREENCANVAS:
226       q->returnValue.i =
227         emscripten_set_canvas_element_size(q->args[0].cp, q->args[1].i, q->args[2].i);
228       break;
229     case EM_PROXIED_JS_FUNCTION:
230       q->returnValue.d =
231         emscripten_receive_on_main_thread_js((int)q->functionPtr, q->args[0].i, &q->args[1].d);
232       break;
233     case EM_FUNC_SIG_V:
234       ((em_func_v)q->functionPtr)();
235       break;
236     case EM_FUNC_SIG_VI:
237       ((em_func_vi)q->functionPtr)(q->args[0].i);
238       break;
239     case EM_FUNC_SIG_VF:
240       ((em_func_vf)q->functionPtr)(q->args[0].f);
241       break;
242     case EM_FUNC_SIG_VII:
243       ((em_func_vii)q->functionPtr)(q->args[0].i, q->args[1].i);
244       break;
245     case EM_FUNC_SIG_VIF:
246       ((em_func_vif)q->functionPtr)(q->args[0].i, q->args[1].f);
247       break;
248     case EM_FUNC_SIG_VFF:
249       ((em_func_vff)q->functionPtr)(q->args[0].f, q->args[1].f);
250       break;
251     case EM_FUNC_SIG_VIII:
252       ((em_func_viii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i);
253       break;
254     case EM_FUNC_SIG_VIIF:
255       ((em_func_viif)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].f);
256       break;
257     case EM_FUNC_SIG_VIFF:
258       ((em_func_viff)q->functionPtr)(q->args[0].i, q->args[1].f, q->args[2].f);
259       break;
260     case EM_FUNC_SIG_VFFF:
261       ((em_func_vfff)q->functionPtr)(q->args[0].f, q->args[1].f, q->args[2].f);
262       break;
263     case EM_FUNC_SIG_VIIII:
264       ((em_func_viiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i);
265       break;
266     case EM_FUNC_SIG_VIIFI:
267       ((em_func_viifi)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].f, q->args[3].i);
268       break;
269     case EM_FUNC_SIG_VIFFF:
270       ((em_func_vifff)q->functionPtr)(q->args[0].i, q->args[1].f, q->args[2].f, q->args[3].f);
271       break;
272     case EM_FUNC_SIG_VFFFF:
273       ((em_func_vffff)q->functionPtr)(q->args[0].f, q->args[1].f, q->args[2].f, q->args[3].f);
274       break;
275     case EM_FUNC_SIG_VIIIII:
276       ((em_func_viiiii)q->functionPtr)(
277         q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i);
278       break;
279     case EM_FUNC_SIG_VIFFFF:
280       ((em_func_viffff)q->functionPtr)(
281         q->args[0].i, q->args[1].f, q->args[2].f, q->args[3].f, q->args[4].f);
282       break;
283     case EM_FUNC_SIG_VIIIIII:
284       ((em_func_viiiiii)q->functionPtr)(
285         q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i);
286       break;
287     case EM_FUNC_SIG_VIIIIIII:
288       ((em_func_viiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i,
289         q->args[4].i, q->args[5].i, q->args[6].i);
290       break;
291     case EM_FUNC_SIG_VIIIIIIII:
292       ((em_func_viiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i,
293         q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i);
294       break;
295     case EM_FUNC_SIG_VIIIIIIIII:
296       ((em_func_viiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i,
297         q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].i);
298       break;
299     case EM_FUNC_SIG_VIIIIIIIIII:
300       ((em_func_viiiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i,
301         q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].i,
302         q->args[9].i);
303       break;
304     case EM_FUNC_SIG_VIIIIIIIIIII:
305       ((em_func_viiiiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i,
306         q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].i,
307         q->args[9].i, q->args[10].i);
308       break;
309     case EM_FUNC_SIG_I:
310       q->returnValue.i = ((em_func_i)q->functionPtr)();
311       break;
312     case EM_FUNC_SIG_II:
313       q->returnValue.i = ((em_func_ii)q->functionPtr)(q->args[0].i);
314       break;
315     case EM_FUNC_SIG_III:
316       q->returnValue.i = ((em_func_iii)q->functionPtr)(q->args[0].i, q->args[1].i);
317       break;
318     case EM_FUNC_SIG_IIII:
319       q->returnValue.i = ((em_func_iiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i);
320       break;
321     case EM_FUNC_SIG_IIIII:
322       q->returnValue.i =
323         ((em_func_iiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i);
324       break;
325     case EM_FUNC_SIG_IIIIII:
326       q->returnValue.i = ((em_func_iiiiii)q->functionPtr)(
327         q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i);
328       break;
329     case EM_FUNC_SIG_IIIIIII:
330       q->returnValue.i = ((em_func_iiiiiii)q->functionPtr)(
331         q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i);
332       break;
333     case EM_FUNC_SIG_IIIIIIII:
334       q->returnValue.i = ((em_func_iiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i,
335         q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i);
336       break;
337     case EM_FUNC_SIG_IIIIIIIII:
338       q->returnValue.i = ((em_func_iiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i,
339         q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i);
340       break;
341     case EM_FUNC_SIG_IIIIIIIIII:
342       q->returnValue.i =
343         ((em_func_iiiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i,
344           q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].i);
345       break;
346     default:
347       assert(0 && "Invalid Emscripten pthread _do_call opcode!");
348   }
349 
350   // If the caller is detached from this operation, it is the main thread's responsibility to free
351   // up the call object.
352   if (q->calleeDelete) {
353     emscripten_async_waitable_close(q);
354     // No need to wake a listener, nothing is listening to this since the call object is detached.
355   } else {
356     // The caller owns this call object, it is listening to it and will free it up.
357     q->operationDone = 1;
358     emscripten_futex_wake(&q->operationDone, INT_MAX);
359   }
360 }
361 
362 #define CALL_QUEUE_SIZE 128
363 
364 typedef struct CallQueue {
365   void* target_thread;
366   em_queued_call** call_queue;
367   int call_queue_head; // Shared data synchronized by call_queue_lock.
368   int call_queue_tail;
369   struct CallQueue* next;
370 } CallQueue;
371 
372 // Currently global to the queue, but this can be improved to be per-queue specific. (TODO: with
373 // lockfree list operations on callQueue_head, or removing the list by moving this data to
374 // pthread_t)
375 static pthread_mutex_t call_queue_lock = PTHREAD_MUTEX_INITIALIZER;
376 static CallQueue* callQueue_head = 0;
377 
GetQueue(void * target)378 static CallQueue* GetQueue(
379   void* target) // Not thread safe, call while having call_queue_lock obtained.
380 {
381   assert(target);
382   CallQueue* q = callQueue_head;
383   while (q && q->target_thread != target)
384     q = q->next;
385   return q;
386 }
387 
GetOrAllocateQueue(void * target)388 static CallQueue* GetOrAllocateQueue(
389   void* target) // Not thread safe, call while having call_queue_lock obtained.
390 {
391   CallQueue* q = GetQueue(target);
392   if (q)
393     return q;
394 
395   q = (CallQueue*)malloc(sizeof(CallQueue));
396   q->target_thread = target;
397   q->call_queue = 0;
398   q->call_queue_head = 0;
399   q->call_queue_tail = 0;
400   q->next = 0;
401   if (callQueue_head) {
402     CallQueue* last = callQueue_head;
403     while (last->next)
404       last = last->next;
405     last->next = q;
406   } else {
407     callQueue_head = q;
408   }
409   return q;
410 }
411 
emscripten_wait_for_call_v(em_queued_call * call,double timeoutMSecs)412 EMSCRIPTEN_RESULT emscripten_wait_for_call_v(em_queued_call* call, double timeoutMSecs) {
413   int r;
414 
415   int done = emscripten_atomic_load_u32(&call->operationDone);
416   if (!done) {
417     double now = emscripten_get_now();
418     double waitEndTime = now + timeoutMSecs;
419     emscripten_set_current_thread_status(EM_THREAD_STATUS_WAITPROXY);
420     while (!done && now < waitEndTime) {
421       r = emscripten_futex_wait(&call->operationDone, 0, waitEndTime - now);
422       done = emscripten_atomic_load_u32(&call->operationDone);
423       now = emscripten_get_now();
424     }
425     emscripten_set_current_thread_status(EM_THREAD_STATUS_RUNNING);
426   }
427   if (done)
428     return EMSCRIPTEN_RESULT_SUCCESS;
429   else
430     return EMSCRIPTEN_RESULT_TIMED_OUT;
431 }
432 
emscripten_wait_for_call_i(em_queued_call * call,double timeoutMSecs,int * outResult)433 EMSCRIPTEN_RESULT emscripten_wait_for_call_i(
434   em_queued_call* call, double timeoutMSecs, int* outResult) {
435   EMSCRIPTEN_RESULT res = emscripten_wait_for_call_v(call, timeoutMSecs);
436   if (res == EMSCRIPTEN_RESULT_SUCCESS && outResult)
437     *outResult = call->returnValue.i;
438   return res;
439 }
440 
441 static pthread_t main_browser_thread_id_ = 0;
442 
emscripten_register_main_browser_thread_id(pthread_t main_browser_thread_id)443 void EMSCRIPTEN_KEEPALIVE emscripten_register_main_browser_thread_id(
444   pthread_t main_browser_thread_id) {
445   main_browser_thread_id_ = main_browser_thread_id;
446 }
447 
emscripten_main_browser_thread_id()448 pthread_t EMSCRIPTEN_KEEPALIVE emscripten_main_browser_thread_id() {
449   return main_browser_thread_id_;
450 }
451 
do_emscripten_dispatch_to_thread(pthread_t target_thread,em_queued_call * call)452 int EMSCRIPTEN_KEEPALIVE do_emscripten_dispatch_to_thread(
453   pthread_t target_thread, em_queued_call* call) {
454   assert(call);
455 
456   // #if PTHREADS_DEBUG // TODO: Create a debug version of pthreads library
457   //	EM_ASM_INT({dump('thread ' + _pthread_self() + ' (ENVIRONMENT_IS_WORKER: ' +
458   //ENVIRONMENT_IS_WORKER + '), queueing call of function enum=' + $0 + '/ptr=' + $1 + ' on thread '
459   //+ $2 + '\n' + new Error().stack)}, call->functionEnum, call->functionPtr, target_thread);
460   // #endif
461 
462   // Can't be a null pointer here, but can't be EM_CALLBACK_THREAD_CONTEXT_MAIN_BROWSER_THREAD
463   // either.
464   assert(target_thread);
465   if (target_thread == EM_CALLBACK_THREAD_CONTEXT_MAIN_BROWSER_THREAD)
466     target_thread = emscripten_main_browser_thread_id();
467 
468   // If we are the target recipient of this message, we can just call the operation directly.
469   if (target_thread == EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD ||
470       target_thread == pthread_self()) {
471     _do_call(call);
472     return 1;
473   }
474 
475   // Add the operation to the call queue of the main runtime thread.
476   pthread_mutex_lock(&call_queue_lock);
477   CallQueue* q = GetOrAllocateQueue(target_thread);
478   if (!q->call_queue)
479     q->call_queue = malloc(
480       sizeof(em_queued_call*) * CALL_QUEUE_SIZE); // Shared data synchronized by call_queue_lock.
481 
482   int head = emscripten_atomic_load_u32((void*)&q->call_queue_head);
483   int tail = emscripten_atomic_load_u32((void*)&q->call_queue_tail);
484   int new_tail = (tail + 1) % CALL_QUEUE_SIZE;
485 
486   while (new_tail == head) { // Queue is full?
487     pthread_mutex_unlock(&call_queue_lock);
488 
489     // If queue of the main browser thread is full, then we wait. (never drop messages for the main
490     // browser thread)
491     if (target_thread == emscripten_main_browser_thread_id()) {
492       emscripten_futex_wait((void*)&q->call_queue_head, head, INFINITY);
493       pthread_mutex_lock(&call_queue_lock);
494       head = emscripten_atomic_load_u32((void*)&q->call_queue_head);
495       tail = emscripten_atomic_load_u32((void*)&q->call_queue_tail);
496       new_tail = (tail + 1) % CALL_QUEUE_SIZE;
497     } else {
498       // For the queues of other threads, just drop the message.
499       // #if DEBUG TODO: a debug build of pthreads library?
500       //			EM_ASM(console.error('Pthread queue overflowed, dropping queued
501       //message to thread. ' + new Error().stack));
502       // #endif
503       em_queued_call_free(call);
504       return 0;
505     }
506   }
507 
508   q->call_queue[tail] = call;
509 
510   // If the call queue was empty, the main runtime thread is likely idle in the browser event loop,
511   // so send a message to it to ensure that it wakes up to start processing the command we have
512   // posted.
513   if (head == tail) {
514     int success = _emscripten_notify_thread_queue(target_thread, emscripten_main_browser_thread_id());
515     // Failed to dispatch the thread, delete the crafted message.
516     if (!success) {
517       em_queued_call_free(call);
518       pthread_mutex_unlock(&call_queue_lock);
519       return 0;
520     }
521   }
522 
523   emscripten_atomic_store_u32((void*)&q->call_queue_tail, new_tail);
524 
525   pthread_mutex_unlock(&call_queue_lock);
526 
527   return 0;
528 }
529 
emscripten_async_run_in_main_thread(em_queued_call * call)530 void EMSCRIPTEN_KEEPALIVE emscripten_async_run_in_main_thread(em_queued_call* call) {
531   do_emscripten_dispatch_to_thread(emscripten_main_browser_thread_id(), call);
532 }
533 
emscripten_sync_run_in_main_thread(em_queued_call * call)534 void EMSCRIPTEN_KEEPALIVE emscripten_sync_run_in_main_thread(em_queued_call* call) {
535   emscripten_async_run_in_main_thread(call);
536 
537   // Enter to wait for the operation to complete.
538   emscripten_wait_for_call_v(call, INFINITY);
539 }
540 
emscripten_sync_run_in_main_thread_0(int function)541 void* EMSCRIPTEN_KEEPALIVE emscripten_sync_run_in_main_thread_0(int function) {
542   em_queued_call q = {function};
543   q.returnValue.vp = 0;
544   emscripten_sync_run_in_main_thread(&q);
545   return q.returnValue.vp;
546 }
547 
emscripten_sync_run_in_main_thread_1(int function,void * arg1)548 void* EMSCRIPTEN_KEEPALIVE emscripten_sync_run_in_main_thread_1(int function, void* arg1) {
549   em_queued_call q = {function};
550   q.args[0].vp = arg1;
551   q.returnValue.vp = 0;
552   emscripten_sync_run_in_main_thread(&q);
553   return q.returnValue.vp;
554 }
555 
emscripten_sync_run_in_main_thread_2(int function,void * arg1,void * arg2)556 void* EMSCRIPTEN_KEEPALIVE emscripten_sync_run_in_main_thread_2(
557   int function, void* arg1, void* arg2) {
558   em_queued_call q = {function};
559   q.args[0].vp = arg1;
560   q.args[1].vp = arg2;
561   q.returnValue.vp = 0;
562   emscripten_sync_run_in_main_thread(&q);
563   return q.returnValue.vp;
564 }
565 
emscripten_sync_run_in_main_thread_xprintf_varargs(int function,int param0,const char * format,...)566 void* EMSCRIPTEN_KEEPALIVE emscripten_sync_run_in_main_thread_xprintf_varargs(
567   int function, int param0, const char* format, ...) {
568   va_list args;
569   va_start(args, format);
570   const int CAP = 128;
571   char str[CAP];
572   char* s = str;
573   int len = vsnprintf(s, CAP, format, args);
574   if (len >= CAP) {
575     s = (char*)malloc(len + 1);
576     va_start(args, format);
577     len = vsnprintf(s, len + 1, format, args);
578   }
579   em_queued_call q = {function};
580   q.args[0].vp = (void*)param0;
581   q.args[1].vp = s;
582   q.returnValue.vp = 0;
583   emscripten_sync_run_in_main_thread(&q);
584   if (s != str)
585     free(s);
586   return q.returnValue.vp;
587 }
588 
emscripten_sync_run_in_main_thread_3(int function,void * arg1,void * arg2,void * arg3)589 void* EMSCRIPTEN_KEEPALIVE emscripten_sync_run_in_main_thread_3(
590   int function, void* arg1, void* arg2, void* arg3) {
591   em_queued_call q = {function};
592   q.args[0].vp = arg1;
593   q.args[1].vp = arg2;
594   q.args[2].vp = arg3;
595   q.returnValue.vp = 0;
596   emscripten_sync_run_in_main_thread(&q);
597   return q.returnValue.vp;
598 }
599 
emscripten_sync_run_in_main_thread_4(int function,void * arg1,void * arg2,void * arg3,void * arg4)600 void* EMSCRIPTEN_KEEPALIVE emscripten_sync_run_in_main_thread_4(
601   int function, void* arg1, void* arg2, void* arg3, void* arg4) {
602   em_queued_call q = {function};
603   q.args[0].vp = arg1;
604   q.args[1].vp = arg2;
605   q.args[2].vp = arg3;
606   q.args[3].vp = arg4;
607   q.returnValue.vp = 0;
608   emscripten_sync_run_in_main_thread(&q);
609   return q.returnValue.vp;
610 }
611 
emscripten_sync_run_in_main_thread_5(int function,void * arg1,void * arg2,void * arg3,void * arg4,void * arg5)612 void* EMSCRIPTEN_KEEPALIVE emscripten_sync_run_in_main_thread_5(
613   int function, void* arg1, void* arg2, void* arg3, void* arg4, void* arg5) {
614   em_queued_call q = {function};
615   q.args[0].vp = arg1;
616   q.args[1].vp = arg2;
617   q.args[2].vp = arg3;
618   q.args[3].vp = arg4;
619   q.args[4].vp = arg5;
620   q.returnValue.vp = 0;
621   emscripten_sync_run_in_main_thread(&q);
622   return q.returnValue.vp;
623 }
624 
emscripten_sync_run_in_main_thread_6(int function,void * arg1,void * arg2,void * arg3,void * arg4,void * arg5,void * arg6)625 void* EMSCRIPTEN_KEEPALIVE emscripten_sync_run_in_main_thread_6(
626   int function, void* arg1, void* arg2, void* arg3, void* arg4, void* arg5, void* arg6) {
627   em_queued_call q = {function};
628   q.args[0].vp = arg1;
629   q.args[1].vp = arg2;
630   q.args[2].vp = arg3;
631   q.args[3].vp = arg4;
632   q.args[4].vp = arg5;
633   q.args[5].vp = arg6;
634   q.returnValue.vp = 0;
635   emscripten_sync_run_in_main_thread(&q);
636   return q.returnValue.vp;
637 }
638 
emscripten_sync_run_in_main_thread_7(int function,void * arg1,void * arg2,void * arg3,void * arg4,void * arg5,void * arg6,void * arg7)639 void* EMSCRIPTEN_KEEPALIVE emscripten_sync_run_in_main_thread_7(int function, void* arg1,
640   void* arg2, void* arg3, void* arg4, void* arg5, void* arg6, void* arg7) {
641   em_queued_call q = {function};
642   q.args[0].vp = arg1;
643   q.args[1].vp = arg2;
644   q.args[2].vp = arg3;
645   q.args[3].vp = arg4;
646   q.args[4].vp = arg5;
647   q.args[5].vp = arg6;
648   q.args[6].vp = arg7;
649   q.returnValue.vp = 0;
650   emscripten_sync_run_in_main_thread(&q);
651   return q.returnValue.vp;
652 }
653 
emscripten_current_thread_process_queued_calls()654 void EMSCRIPTEN_KEEPALIVE emscripten_current_thread_process_queued_calls() {
655   // #if PTHREADS_DEBUG == 2
656   //	EM_ASM(console.error('thread ' + _pthread_self() + ':
657   //emscripten_current_thread_process_queued_calls(), ' + new Error().stack));
658   // #endif
659 
660   // TODO: Under certain conditions we may want to have a nesting guard also for pthreads (and it
661   // will certainly be cleaner that way), but we don't yet have TLS variables outside
662   // pthread_set/getspecific, so convert this to TLS after TLS is implemented.
663   static int bool_main_thread_inside_nested_process_queued_calls = 0;
664 
665   if (emscripten_is_main_browser_thread()) {
666     // It is possible that when processing a queued call, the call flow leads back to calling this
667     // function in a nested fashion! Therefore this scenario must explicitly be detected, and
668     // processing the queue must be avoided if we are nesting, or otherwise the same queued calls
669     // would be processed again and again.
670     if (bool_main_thread_inside_nested_process_queued_calls)
671       return;
672     // This must be before pthread_mutex_lock(), since pthread_mutex_lock() can call back to this
673     // function.
674     bool_main_thread_inside_nested_process_queued_calls = 1;
675   }
676 
677   pthread_mutex_lock(&call_queue_lock);
678   CallQueue* q = GetQueue(pthread_self());
679   if (!q) {
680     pthread_mutex_unlock(&call_queue_lock);
681     if (emscripten_is_main_browser_thread())
682       bool_main_thread_inside_nested_process_queued_calls = 0;
683     return;
684   }
685 
686   int head = emscripten_atomic_load_u32((void*)&q->call_queue_head);
687   int tail = emscripten_atomic_load_u32((void*)&q->call_queue_tail);
688   while (head != tail) {
689     // Assume that the call is heavy, so unlock access to the call queue while it is being
690     // performed.
691     pthread_mutex_unlock(&call_queue_lock);
692     _do_call(q->call_queue[head]);
693     pthread_mutex_lock(&call_queue_lock);
694 
695     head = (head + 1) % CALL_QUEUE_SIZE;
696     emscripten_atomic_store_u32((void*)&q->call_queue_head, head);
697     tail = emscripten_atomic_load_u32((void*)&q->call_queue_tail);
698   }
699   pthread_mutex_unlock(&call_queue_lock);
700 
701   // If the queue was full and we had waiters pending to get to put data to queue, wake them up.
702   emscripten_futex_wake((void*)&q->call_queue_head, 0x7FFFFFFF);
703 
704   if (emscripten_is_main_browser_thread())
705     bool_main_thread_inside_nested_process_queued_calls = 0;
706 }
707 
emscripten_main_thread_process_queued_calls()708 void EMSCRIPTEN_KEEPALIVE emscripten_main_thread_process_queued_calls() {
709   if (!emscripten_is_main_runtime_thread())
710     return;
711 
712   emscripten_current_thread_process_queued_calls();
713 }
714 
emscripten_sync_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig,void * func_ptr,...)715 int emscripten_sync_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void* func_ptr, ...) {
716   int numArguments = EM_FUNC_SIG_NUM_FUNC_ARGUMENTS(sig);
717   em_queued_call q = {sig, func_ptr};
718 
719   EM_FUNC_SIGNATURE argumentsType = sig & EM_FUNC_SIG_ARGUMENTS_TYPE_MASK;
720   va_list args;
721   va_start(args, func_ptr);
722   for (int i = 0; i < numArguments; ++i) {
723     switch ((argumentsType & EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_MASK)) {
724       case EM_FUNC_SIG_PARAM_I:
725         q.args[i].i = va_arg(args, int);
726         break;
727       case EM_FUNC_SIG_PARAM_I64:
728         q.args[i].i64 = va_arg(args, int64_t);
729         break;
730       case EM_FUNC_SIG_PARAM_F:
731         q.args[i].f = (float)va_arg(args, double);
732         break;
733       case EM_FUNC_SIG_PARAM_D:
734         q.args[i].d = va_arg(args, double);
735         break;
736     }
737     argumentsType >>= EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_SHIFT;
738   }
739   va_end(args);
740   emscripten_sync_run_in_main_thread(&q);
741   return q.returnValue.i;
742 }
743 
emscripten_run_in_main_runtime_thread_js(int index,int num_args,double * buffer,int sync)744 EMSCRIPTEN_KEEPALIVE double emscripten_run_in_main_runtime_thread_js(int index, int num_args, double* buffer, int sync) {
745   em_queued_call q;
746   em_queued_call *c;
747   if (sync) {
748     q.operationDone = 0;
749     q.satelliteData = 0;
750     c = &q;
751   } else {
752     c = em_queued_call_malloc();
753   }
754   c->calleeDelete = 1-sync;
755   c->functionEnum = EM_PROXIED_JS_FUNCTION;
756   c->functionPtr = (void*)index;
757   // We write out the JS doubles into args[], which must be of appropriate size - JS will assume that.
758   assert(sizeof(em_variant_val) == sizeof(double));
759   assert(num_args+1 <= EM_QUEUED_JS_CALL_MAX_ARGS);
760   c->args[0].i = num_args;
761   for (int i = 0; i < num_args; i++) {
762     c->args[i+1].d = buffer[i];
763   }
764 
765   if (sync) {
766     emscripten_sync_run_in_main_thread(&q);
767     return q.returnValue.d;
768   } else {
769     // 'async' runs are fire and forget, where the caller detaches itself from the call object after
770     // returning here, and it is the callee's responsibility to free up the memory after the call
771     // has been performed.
772     emscripten_async_run_in_main_thread(c);
773     return 0;
774   }
775 }
776 
emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig,void * func_ptr,...)777 void emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void* func_ptr, ...) {
778   int numArguments = EM_FUNC_SIG_NUM_FUNC_ARGUMENTS(sig);
779   em_queued_call* q = em_queued_call_malloc();
780   if (!q)
781     return;
782   q->functionEnum = sig;
783   q->functionPtr = func_ptr;
784 
785   EM_FUNC_SIGNATURE argumentsType = sig & EM_FUNC_SIG_ARGUMENTS_TYPE_MASK;
786   va_list args;
787   va_start(args, func_ptr);
788   for (int i = 0; i < numArguments; ++i) {
789     switch ((argumentsType & EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_MASK)) {
790       case EM_FUNC_SIG_PARAM_I:
791         q->args[i].i = va_arg(args, int);
792         break;
793       case EM_FUNC_SIG_PARAM_I64:
794         q->args[i].i64 = va_arg(args, int64_t);
795         break;
796       case EM_FUNC_SIG_PARAM_F:
797         q->args[i].f = (float)va_arg(args, double);
798         break;
799       case EM_FUNC_SIG_PARAM_D:
800         q->args[i].d = va_arg(args, double);
801         break;
802     }
803     argumentsType >>= EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_SHIFT;
804   }
805   va_end(args);
806   // 'async' runs are fire and forget, where the caller detaches itself from the call object after
807   // returning here, and it is the callee's responsibility to free up the memory after the call has
808   // been performed.
809   q->calleeDelete = 1;
810   emscripten_async_run_in_main_thread(q);
811 }
812 
emscripten_async_waitable_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig,void * func_ptr,...)813 em_queued_call* emscripten_async_waitable_run_in_main_runtime_thread_(
814   EM_FUNC_SIGNATURE sig, void* func_ptr, ...) {
815   int numArguments = EM_FUNC_SIG_NUM_FUNC_ARGUMENTS(sig);
816   em_queued_call* q = em_queued_call_malloc();
817   if (!q)
818     return NULL;
819   q->functionEnum = sig;
820   q->functionPtr = func_ptr;
821 
822   EM_FUNC_SIGNATURE argumentsType = sig & EM_FUNC_SIG_ARGUMENTS_TYPE_MASK;
823   va_list args;
824   va_start(args, func_ptr);
825   for (int i = 0; i < numArguments; ++i) {
826     switch ((argumentsType & EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_MASK)) {
827       case EM_FUNC_SIG_PARAM_I:
828         q->args[i].i = va_arg(args, int);
829         break;
830       case EM_FUNC_SIG_PARAM_I64:
831         q->args[i].i64 = va_arg(args, int64_t);
832         break;
833       case EM_FUNC_SIG_PARAM_F:
834         q->args[i].f = (float)va_arg(args, double);
835         break;
836       case EM_FUNC_SIG_PARAM_D:
837         q->args[i].d = va_arg(args, double);
838         break;
839     }
840     argumentsType >>= EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_SHIFT;
841   }
842   va_end(args);
843   // 'async waitable' runs are waited on by the caller, so the call object needs to remain alive for
844   // the caller to access it after the operation is done. The caller is responsible in cleaning up
845   // the object after done.
846   q->calleeDelete = 0;
847   emscripten_async_run_in_main_thread(q);
848   return q;
849 }
850 
_emscripten_call_on_thread(int forceAsync,pthread_t targetThread,EM_FUNC_SIGNATURE sig,void * func_ptr,void * satellite,...)851 int EMSCRIPTEN_KEEPALIVE _emscripten_call_on_thread(
852   int forceAsync,
853   pthread_t targetThread, EM_FUNC_SIGNATURE sig, void* func_ptr, void* satellite, ...) {
854   int numArguments = EM_FUNC_SIG_NUM_FUNC_ARGUMENTS(sig);
855   em_queued_call* q = em_queued_call_malloc();
856   assert(q);
857   // TODO: handle errors in a better way, this pattern appears in several places
858   //       in this file. The current behavior makes the calling thread hang as
859   //       it waits (for synchronous calls).
860   // If we failed to allocate, return 0 which means we did not execute anything
861   // (we also never will in that case).
862   if (!q)
863     return 0;
864   q->functionEnum = sig;
865   q->functionPtr = func_ptr;
866   q->satelliteData = satellite;
867 
868   EM_FUNC_SIGNATURE argumentsType = sig & EM_FUNC_SIG_ARGUMENTS_TYPE_MASK;
869   va_list args;
870   va_start(args, satellite);
871   for (int i = 0; i < numArguments; ++i) {
872     switch ((argumentsType & EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_MASK)) {
873       case EM_FUNC_SIG_PARAM_I:
874         q->args[i].i = va_arg(args, int);
875         break;
876       case EM_FUNC_SIG_PARAM_I64:
877         q->args[i].i64 = va_arg(args, int64_t);
878         break;
879       case EM_FUNC_SIG_PARAM_F:
880         q->args[i].f = (float)va_arg(args, double);
881         break;
882       case EM_FUNC_SIG_PARAM_D:
883         q->args[i].d = va_arg(args, double);
884         break;
885     }
886     argumentsType >>= EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_SHIFT;
887   }
888   va_end(args);
889 
890   // 'async' runs are fire and forget, where the caller detaches itself from the call object after
891   // returning here, and it is the callee's responsibility to free up the memory after the call has
892   // been performed.
893   // Note that the call here might not be async if on the same thread, but for
894   // consistency use the same convention of calleeDelete.
895   q->calleeDelete = 1;
896   // The called function will not be async if we are on the same thread; force
897   // async if the user asked for that.
898   if (forceAsync) {
899     EM_ASM({
900       setTimeout(function() {
901         _do_emscripten_dispatch_to_thread($0, $1);
902       }, 0);
903     }, targetThread, q);
904     return 0;
905   } else {
906     return do_emscripten_dispatch_to_thread(targetThread, q);
907   }
908 }
909 
llvm_memory_barrier()910 void llvm_memory_barrier() { emscripten_atomic_fence(); }
911 
llvm_atomic_load_add_i32_p0i32(int * ptr,int delta)912 int llvm_atomic_load_add_i32_p0i32(int* ptr, int delta) {
913   return emscripten_atomic_add_u32(ptr, delta);
914 }
915 
916 typedef struct main_args {
917   int argc;
918   char** argv;
919 } main_args;
920 
921 extern int __call_main(int argc, char** argv);
922 
__emscripten_thread_main(void * param)923 void* __emscripten_thread_main(void* param) {
924   emscripten_set_thread_name(pthread_self(),
925     "Application main thread"); // This is the main runtime thread for the application.
926   main_args* args = (main_args*)param;
927   return (void*)__call_main(args->argc, args->argv);
928 }
929 
930 static main_args _main_arguments;
931 
proxy_main(int argc,char ** argv)932 int proxy_main(int argc, char** argv) {
933   if (emscripten_has_threading_support()) {
934     pthread_attr_t attr;
935     pthread_attr_init(&attr);
936     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
937     // Use TOTAL_STACK for the stack size, which is the normal size of the stack
938     // that main() would have without PROXY_TO_PTHREAD.
939     pthread_attr_setstacksize(&attr, EM_ASM_INT({ return TOTAL_STACK }));
940     // Pass special ID -1 to the list of transferred canvases to denote that the thread creation
941     // should instead take a list of canvases that are specified from the command line with
942     // -s OFFSCREENCANVASES_TO_PTHREAD linker flag.
943     emscripten_pthread_attr_settransferredcanvases(&attr, (const char*)-1);
944     _main_arguments.argc = argc;
945     _main_arguments.argv = argv;
946     pthread_t thread;
947     int rc = pthread_create(&thread, &attr, __emscripten_thread_main, (void*)&_main_arguments);
948     pthread_attr_destroy(&attr);
949     if (rc) {
950       // Proceed by running main() on the main browser thread as a fallback.
951       return __call_main(_main_arguments.argc, _main_arguments.argv);
952     }
953     return 0;
954   } else {
955     return __call_main(_main_arguments.argc, _main_arguments.argv);
956   }
957 }
958 
959 weak_alias(__pthread_testcancel, pthread_testcancel);
960