Path: blob/main/system/lib/pthread/library_pthread_stub.c
6175 views
/*1* Copyright 2019 The Emscripten Authors. All rights reserved.2* Emscripten is available under two separate licenses, the MIT license and the3* University of Illinois/NCSA Open Source License. Both these licenses can be4* found in the LICENSE file.5*/67#include <errno.h>8#include <stdbool.h>9#include <pthread.h>10#include <semaphore.h>11#include <stdint.h>12#include <stdlib.h>13#include <unistd.h>14#include "pthread_impl.h"15#include <emscripten/stack.h>16#include <emscripten/threading.h>17#include <emscripten/emscripten.h>1819int emscripten_has_threading_support() { return 0; }2021int emscripten_num_logical_cores() { return 1; }2223int emscripten_futex_wait(24volatile void /*uint32_t*/* addr, uint32_t val, double maxWaitMilliseconds) {25// nop26return 0; // success27}2829int emscripten_futex_wake(volatile void /*uint32_t*/* addr, int count) {30// nop31return 0; // success32}3334int emscripten_is_main_runtime_thread() { return 1; }3536void emscripten_main_thread_process_queued_calls() {37// nop38}3940void emscripten_current_thread_process_queued_calls() {41// nop42}4344static void dummy(double now)45{46}4748weak_alias(dummy, _emscripten_check_timers);4950void _emscripten_yield(double now) {51_emscripten_check_timers(now);52}5354int pthread_mutex_init(55pthread_mutex_t* __restrict mutex, const pthread_mutexattr_t* __restrict attr) {56return 0;57}5859int __pthread_mutex_lock(pthread_mutex_t* mutex) { return 0; }6061weak_alias(__pthread_mutex_lock, pthread_mutex_lock);6263int __pthread_mutex_unlock(pthread_mutex_t* mutex) { return 0; }6465weak_alias(__pthread_mutex_unlock, pthread_mutex_unlock);6667int __pthread_mutex_trylock(pthread_mutex_t* mutex) { return 0; }6869weak_alias(__pthread_mutex_trylock, pthread_mutex_trylock);7071struct timespec;7273int __pthread_mutex_timedlock(74pthread_mutex_t* __restrict mutex, const struct timespec* __restrict t) {75return 0;76}7778weak_alias(__pthread_mutex_timedlock, pthread_mutex_timedlock);7980int pthread_mutex_destroy(pthread_mutex_t* mutex) { return 0; }8182int pthread_mutex_consistent(pthread_mutex_t* mutex) { return 0; }8384int pthread_barrier_init(85pthread_barrier_t* __restrict mutex, const pthread_barrierattr_t* __restrict attr, unsigned u) {86return 0;87}8889int pthread_barrier_destroy(pthread_barrier_t* mutex) { return 0; }9091int pthread_barrier_wait(pthread_barrier_t* mutex) { return 0; }9293int __pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) {94// ENOTSUP, while not mentioned in the pthread_create docs, does better95// describe the situation.96// See https://github.com/WebAssembly/wasi-libc/pull/716 for discussion97// on this error code vs, for example, EAGAIN.98return ENOTSUP;99}100101weak_alias(__pthread_create, emscripten_builtin_pthread_create);102weak_alias(__pthread_create, pthread_create);103104int __pthread_join(pthread_t thread, void **retval) {105return EINVAL;106}107108weak_alias(__pthread_join, emscripten_builtin_pthread_join);109weak_alias(__pthread_join, pthread_join);110111static void* tls_entries[PTHREAD_KEYS_MAX];112static bool tls_key_used[PTHREAD_KEYS_MAX];113114int __pthread_key_create(pthread_key_t* key, void (*destructor)(void*)) {115if (key == 0) {116return EINVAL;117}118// Find empty spot.119for (pthread_key_t entry = 0; entry < PTHREAD_KEYS_MAX; entry++) {120if (!tls_key_used[entry]) {121tls_key_used[entry] = true;122tls_entries[entry] = NULL;123*key = entry;124return 0;125}126}127// No empty spots, return an error128return EAGAIN;129}130131int __pthread_key_delete(pthread_key_t key) {132if (key < 0 || key >= PTHREAD_KEYS_MAX) {133return EINVAL;134}135if (!tls_key_used[key]) {136return EINVAL;137}138tls_key_used[key] = false;139tls_entries[key] = NULL;140return 0;141}142143weak_alias(__pthread_key_delete, pthread_key_delete);144weak_alias(__pthread_key_create, pthread_key_create);145146void* pthread_getspecific(pthread_key_t key) {147if (key < 0 || key >= PTHREAD_KEYS_MAX) {148return NULL;149}150if (!tls_key_used[key]) {151return NULL;152}153return tls_entries[key];154}155156int pthread_setspecific(pthread_key_t key, const void* value) {157if (key < 0 || key >= PTHREAD_KEYS_MAX) {158return EINVAL;159}160if (!tls_key_used[key]) {161return EINVAL;162}163tls_entries[key] = (void*)value;164return 0;165}166167/*magic number to detect if we have not run yet*/168#define PTHREAD_ONCE_MAGIC_ID 0x13579BDF169170int __pthread_once(pthread_once_t* once_control, void (*init_routine)(void)) {171if (*once_control != PTHREAD_ONCE_MAGIC_ID) {172init_routine();173*once_control = PTHREAD_ONCE_MAGIC_ID;174}175return 0;176}177178weak_alias(__pthread_once, pthread_once);179180int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) {181return 0;182}183184int pthread_cond_signal(pthread_cond_t *cond) {185return 0;186}187188int __private_cond_signal(pthread_cond_t *c, int n) {189return 0;190}191192int pthread_cond_broadcast(pthread_cond_t *cond) {193return 0;194}195196int pthread_cond_init(pthread_cond_t *__restrict x, const pthread_condattr_t *__restrict y) {197return 0;198}199200int pthread_cond_destroy(pthread_cond_t * x) {201return 0;202}203204int __pthread_cond_timedwait(pthread_cond_t *__restrict x, pthread_mutex_t *__restrict y, const struct timespec *__restrict z) {205return 0;206}207208weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait);209210int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) {211return 0;212}213214int pthread_cancel(pthread_t thread) {215return 0;216}217218void pthread_testcancel() {}219220_Noreturn void __pthread_exit(void* status) {221exit(0);222}223224weak_alias(__pthread_exit, emscripten_builtin_pthread_exit);225weak_alias(__pthread_exit, pthread_exit);226227int __pthread_detach(pthread_t t) {228return 0;229}230231weak_alias(__pthread_detach, emscripten_builtin_pthread_detach);232weak_alias(__pthread_detach, pthread_detach);233weak_alias(__pthread_detach, thrd_detach);234235// pthread_equal is defined as a macro in C, as a function for C++; undef it236// here so we define the function for C++ that links to us.237#ifdef pthread_equal238#undef pthread_equal239#endif240241int pthread_equal(pthread_t t1, pthread_t t2) {242return t1 == t2;243}244245int pthread_mutexattr_init(pthread_mutexattr_t *attr) {246return 0;247}248249int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol) {250return 0;251}252253int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) {254return 0;255}256257int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) {258return 0;259}260261int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) {262// XXX implement if/when getpshared is required263return 0;264}265266int pthread_condattr_init(pthread_condattr_t * attr) {267return 0;268}269270int pthread_condattr_destroy(pthread_condattr_t *attr) {271return 0;272}273274int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clk) {275return 0;276}277278int pthread_condattr_setpshared(pthread_condattr_t *attr, int shared) {279return 0;280}281282int pthread_setcancelstate(int state, int* oldstate) {283return 0;284}285286int pthread_setcanceltype(int type, int* oldtype) {287return 0;288}289290int pthread_rwlock_init(pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr) {291return 0;292}293294int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) {295return 0;296}297298int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) {299return 0;300}301302int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock) {303return 0;304}305306int pthread_rwlock_timedrdlock(pthread_rwlock_t* rwlock, const struct timespec* abs_timeout) {307return 0;308}309310int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) {311return 0;312}313314int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) {315return 0;316}317318int pthread_rwlock_timedwrlock(pthread_rwlock_t* rwlock, const struct timespec* abs_timeout) {319return 0;320}321322int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) {323return 0;324}325326int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) {327return 0;328}329330int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr) {331return 0;332}333334int pthread_rwlockattr_setpshared(pthread_rwlockattr_t* attr, int pshared) {335return 0;336}337338int pthread_spin_init(pthread_spinlock_t *lock, int pshared) {339return 0;340}341342int pthread_spin_destroy(pthread_spinlock_t *lock) {343return 0;344}345346int pthread_spin_lock(pthread_spinlock_t *lock) {347return 0;348}349350int pthread_spin_trylock(pthread_spinlock_t *lock) {351return 0;352}353354int pthread_spin_unlock(pthread_spinlock_t *lock) {355return 0;356}357358int sem_init(sem_t *sem, int pshared, unsigned int value) {359return 0;360}361362int sem_post(sem_t *sem) {363return 0;364}365366int sem_wait(sem_t *sem) {367return 0;368}369370int sem_trywait(sem_t *sem) {371return 0;372}373374int sem_destroy(sem_t *sem) {375return 0;376}377378void __wait(volatile int *addr, volatile int *waiters, int val, int priv) {}379380void __lock(void* ptr) {}381382void __unlock(void* ptr) {}383384void __acquire_ptc() {}385386void __release_ptc() {}387388// When pthreads is not enabled, we can't use the Atomics futex api to do389// proper sleeps, so simulate a busy spin wait loop instead.390void emscripten_thread_sleep(double msecs) {391double start = emscripten_get_now();392double now = start;393do {394_emscripten_yield(now);395now = emscripten_get_now();396} while (now - start < msecs);397}398399400