/* * Copyright 2015 The Emscripten Authors. All rights reserved. * Emscripten is available under two separate licenses, the MIT license and the * University of Illinois/NCSA Open Source License. Both these licenses can be * found in the LICENSE file. */ #define _GNU_SOURCE #include "../internal/libc.h" #include "../internal/pthread_impl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "threading_internal.h" #include "emscripten_internal.h" int emscripten_pthread_attr_gettransferredcanvases(const pthread_attr_t* a, const char** str) { *str = a->_a_transferredcanvases; return 0; } int emscripten_pthread_attr_settransferredcanvases(pthread_attr_t* a, const char* str) { a->_a_transferredcanvases = str; return 0; } int sched_get_priority_max(int policy) { // Web workers do not actually support prioritizing threads, // but mimic values that Linux apparently reports, see // http://man7.org/linux/man-pages/man2/sched_get_priority_min.2.html if (policy == SCHED_FIFO || policy == SCHED_RR) return 99; else return 0; } int sched_get_priority_min(int policy) { // Web workers do not actually support prioritizing threads, // but mimic values that Linux apparently reports, see // http://man7.org/linux/man-pages/man2/sched_get_priority_min.2.html if (policy == SCHED_FIFO || policy == SCHED_RR) return 1; else return 0; } int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *restrict attr, int *restrict prioceiling) { // Not supported either in Emscripten or musl, return a faked value. if (prioceiling) *prioceiling = 99; return 0; } int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling) { // Not supported either in Emscripten or musl, return an error. return EPERM; } static uint32_t dummyZeroAddress = 0; void emscripten_thread_sleep(double msecs) { double now = emscripten_get_now(); double target = now + msecs; // If we have less than this many msecs left to wait, busy spin that instead. double min_ms_slice_to_sleep = 0.1; // runtime thread may need to run proxied calls, so sleep in very small slices to be responsive. double max_ms_slice_to_sleep = emscripten_is_main_runtime_thread() ? 1 : 100; emscripten_conditional_set_current_thread_status( EM_THREAD_STATUS_RUNNING, EM_THREAD_STATUS_SLEEPING); do { // Keep processing the main loop of the calling thread. __pthread_testcancel(); // pthreads spec: sleep is a cancellation point, so must test if this // thread is cancelled during the sleep. emscripten_current_thread_process_queued_calls(); now = emscripten_get_now(); double ms_to_sleep = target - now; if (ms_to_sleep < min_ms_slice_to_sleep) continue; if (ms_to_sleep > max_ms_slice_to_sleep) ms_to_sleep = max_ms_slice_to_sleep; emscripten_futex_wait(&dummyZeroAddress, 0, ms_to_sleep); now = emscripten_get_now(); } while (now < target); emscripten_conditional_set_current_thread_status( EM_THREAD_STATUS_SLEEPING, EM_THREAD_STATUS_RUNNING); } static struct pthread __main_pthread; pthread_t emscripten_main_runtime_thread_id() { return &__main_pthread; } void emscripten_current_thread_process_queued_calls() { emscripten_proxy_execute_queue(emscripten_proxy_get_system_queue()); } void emscripten_main_thread_process_queued_calls() { assert(emscripten_is_main_runtime_thread()); emscripten_current_thread_process_queued_calls(); } int _emscripten_thread_is_valid(pthread_t thread) { return thread->self == thread; } static void *dummy_tsd[1] = { 0 }; weak_alias(dummy_tsd, __pthread_tsd_main); // See system/lib/README.md for static constructor ordering. __attribute__((constructor(48))) void __emscripten_init_main_thread(void) { __emscripten_init_main_thread_js(&__main_pthread); // The pthread struct has a field that points to itself - this is used as // a magic ID to detect whether the pthread_t structure is 'alive'. __main_pthread.self = &__main_pthread; __main_pthread.stack = (void*)emscripten_stack_get_base(); __main_pthread.stack_size = emscripten_stack_get_base() - emscripten_stack_get_end(); __main_pthread.detach_state = DT_JOINABLE; // pthread struct robust_list head should point to itself. __main_pthread.robust_list.head = &__main_pthread.robust_list.head; // Main thread ID is always 1. It can't be 0 because musl assumes // tid is always non-zero. __main_pthread.tid = getpid(); __main_pthread.locale = &libc.global_locale; // pthread struct prev and next should initially point to itself (see __init_tp), // this is used by pthread_key_delete for deleting thread-specific data. __main_pthread.next = __main_pthread.prev = &__main_pthread; __main_pthread.tsd = (void **)__pthread_tsd_main; _emscripten_thread_mailbox_init(&__main_pthread); _emscripten_thread_mailbox_await(&__main_pthread); }