From 90a0057d330cd5cad26cd1013192f0a94d95d781 Mon Sep 17 00:00:00 2001 From: Xu Jun <693788454@qq.com> Date: Tue, 25 Jan 2022 09:28:02 +0800 Subject: [PATCH] Implement pthread_cond_broadcast wrapper for lib-pthread (#982) Implement pthread_cond_broadcast wrapper for lib-pthread - support pthread_cond_broadcast wrapper for posix/linux-sgx/windows - update document for building multi-thread wasm app with emcc --- .../lib-pthread/lib_pthread_wrapper.c | 19 ++++++ .../platform/common/posix/posix_thread.c | 11 ++++ .../platform/include/platform_api_extension.h | 10 +++ core/shared/platform/linux-sgx/sgx_thread.c | 13 ++++ core/shared/platform/windows/win_thread.c | 18 ++++++ doc/pthread_library.md | 11 ++++ .../libc-builtin-sysroot/include/pthread.h | 64 +++++++++++++------ 7 files changed, 125 insertions(+), 21 deletions(-) diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index 3f636863..90b60394 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -718,6 +718,13 @@ pthread_self_wrapper(wasm_exec_env_t exec_env) return args->info_node->handle; } +/* emcc use __pthread_self rather than pthread_self */ +static int32 +__pthread_self_wrapper(wasm_exec_env_t exec_env) +{ + return pthread_self_wrapper(exec_env); +} + static void pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset) { @@ -926,6 +933,16 @@ pthread_cond_signal_wrapper(wasm_exec_env_t exec_env, uint32 *cond) return os_cond_signal(info_node->u.cond); } +static int32 +pthread_cond_broadcast_wrapper(wasm_exec_env_t exec_env, uint32 *cond) +{ + ThreadInfoNode *info_node = get_thread_info(exec_env, *cond); + if (!info_node || info_node->type != T_COND) + return -1; + + return os_cond_broadcast(info_node->u.cond); +} + static int32 pthread_cond_destroy_wrapper(wasm_exec_env_t exec_env, uint32 *cond) { @@ -1079,6 +1096,7 @@ static NativeSymbol native_symbols_lib_pthread[] = { REG_NATIVE_FUNC(pthread_detach, "(i)i"), REG_NATIVE_FUNC(pthread_cancel, "(i)i"), REG_NATIVE_FUNC(pthread_self, "()i"), + REG_NATIVE_FUNC(__pthread_self, "()i"), REG_NATIVE_FUNC(pthread_exit, "(i)"), REG_NATIVE_FUNC(pthread_mutex_init, "(**)i"), REG_NATIVE_FUNC(pthread_mutex_lock, "(*)i"), @@ -1088,6 +1106,7 @@ static NativeSymbol native_symbols_lib_pthread[] = { REG_NATIVE_FUNC(pthread_cond_wait, "(**)i"), REG_NATIVE_FUNC(pthread_cond_timedwait, "(**I)i"), REG_NATIVE_FUNC(pthread_cond_signal, "(*)i"), + REG_NATIVE_FUNC(pthread_cond_broadcast, "(*)i"), REG_NATIVE_FUNC(pthread_cond_destroy, "(*)i"), REG_NATIVE_FUNC(pthread_key_create, "(*i)i"), REG_NATIVE_FUNC(pthread_setspecific, "(ii)i"), diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 0ae231c1..29839036 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -262,6 +262,17 @@ os_cond_signal(korp_cond *cond) return BHT_OK; } +int +os_cond_broadcast(korp_cond *cond) +{ + assert(cond); + + if (pthread_cond_broadcast(cond) != BHT_OK) + return BHT_ERROR; + + return BHT_OK; +} + int os_thread_join(korp_tid thread, void **value_ptr) { diff --git a/core/shared/platform/include/platform_api_extension.h b/core/shared/platform/include/platform_api_extension.h index 5a7e825c..cd3c7e95 100644 --- a/core/shared/platform/include/platform_api_extension.h +++ b/core/shared/platform/include/platform_api_extension.h @@ -179,6 +179,16 @@ os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds); int os_cond_signal(korp_cond *cond); +/** + * Broadcast the condition variable + * + * @param cond condition variable + * + * @return 0 if success + */ +int +os_cond_broadcast(korp_cond *cond); + /**************************************************** * Section 2 * * Socket support * diff --git a/core/shared/platform/linux-sgx/sgx_thread.c b/core/shared/platform/linux-sgx/sgx_thread.c index fbf407be..1cb2f5d0 100644 --- a/core/shared/platform/linux-sgx/sgx_thread.c +++ b/core/shared/platform/linux-sgx/sgx_thread.c @@ -164,6 +164,19 @@ os_cond_signal(korp_cond *cond) return BHT_OK; } +int +os_cond_broadcast(korp_cond *cond) +{ +#ifndef SGX_DISABLE_PTHREAD + assert(cond); + + if (pthread_cond_broadcast(cond) != BHT_OK) + return BHT_ERROR; + +#endif + return BHT_OK; +} + int os_thread_join(korp_tid thread, void **value_ptr) { diff --git a/core/shared/platform/windows/win_thread.c b/core/shared/platform/windows/win_thread.c index 73b04dfa..0cfc5dfb 100644 --- a/core/shared/platform/windows/win_thread.c +++ b/core/shared/platform/windows/win_thread.c @@ -567,6 +567,24 @@ os_cond_signal(korp_cond *cond) return BHT_OK; } +int +os_cond_broadcast(korp_cond *cond) +{ + /* Signal all of the wait node of wait list */ + os_mutex_lock(&cond->wait_list_lock); + if (cond->thread_wait_list) { + os_thread_wait_node *p = cond->thread_wait_list; + while (p) { + os_sem_signal(&p->sem); + p = p->next; + } + } + + os_mutex_unlock(&cond->wait_list_lock); + + return BHT_OK; +} + static os_thread_local_attribute uint8 *thread_stack_boundary = NULL; static ULONG diff --git a/doc/pthread_library.md b/doc/pthread_library.md index b1de6b10..cf79214e 100644 --- a/doc/pthread_library.md +++ b/doc/pthread_library.md @@ -80,8 +80,17 @@ Then build the program with this command: **Build with EMCC** +> Note: This document is based on `emcc 2.0.26`, other version may not work with these commands + EMCC's `-pthread` option is not compatible with standalone mode, we need to pass `-mbulk-memory -matomics` to the compiler and `--shared-memory,--no-check-features` to linker manually +EMCC provides some empty implementation for pthread related APIs, we need to remove them from emcc's libc. +``` bash +cd ${emsdk_dir}/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten +emar d libc.a library_pthread_stub.o +emranlib libc.a +``` + ``` bash emcc -O3 -mbulk-memory -matomics -s MALLOC="none" \ -Wl,--export=__data_end,--export=__heap_base \ @@ -166,6 +175,8 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, int pthread_cond_signal(pthread_cond_t *cond); +int pthread_cond_broadcast(pthread_cond_t *cond); + int pthread_cond_destroy(pthread_cond_t *cond); /* Pthread key APIs */ diff --git a/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h b/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h index 71b7fce8..10b3978e 100644 --- a/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h +++ b/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h @@ -19,48 +19,70 @@ typedef unsigned int pthread_cond_t; typedef unsigned int pthread_key_t; /* Thread APIs */ -int pthread_create(pthread_t *thread, const void *attr, - void *(*start_routine) (void *), void *arg); +int +pthread_create(pthread_t *thread, const void *attr, + void *(*start_routine)(void *), void *arg); -int pthread_join(pthread_t thread, void **retval); +int +pthread_join(pthread_t thread, void **retval); -int pthread_detach(pthread_t thread); +int +pthread_detach(pthread_t thread); -int pthread_cancel(pthread_t thread); +int +pthread_cancel(pthread_t thread); -pthread_t pthread_self(void); +pthread_t +pthread_self(void); -void pthread_exit(void *retval); +void +pthread_exit(void *retval); /* Mutex APIs */ -int pthread_mutex_init(pthread_mutex_t *mutex, const void *attr); +int +pthread_mutex_init(pthread_mutex_t *mutex, const void *attr); -int pthread_mutex_lock(pthread_mutex_t *mutex); +int +pthread_mutex_lock(pthread_mutex_t *mutex); -int pthread_mutex_unlock(pthread_mutex_t *mutex); +int +pthread_mutex_unlock(pthread_mutex_t *mutex); -int pthread_mutex_destroy(pthread_mutex_t *mutex); +int +pthread_mutex_destroy(pthread_mutex_t *mutex); /* Cond APIs */ -int pthread_cond_init(pthread_cond_t *cond, const void *attr); +int +pthread_cond_init(pthread_cond_t *cond, const void *attr); -int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); +int +pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); -int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, - uint64_t useconds); +int +pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + uint64_t useconds); -int pthread_cond_signal(pthread_cond_t *cond); +int +pthread_cond_signal(pthread_cond_t *cond); -int pthread_cond_destroy(pthread_cond_t *cond); +int +pthread_cond_broadcast(pthread_cond_t *cond); + +int +pthread_cond_destroy(pthread_cond_t *cond); /* Pthread key APIs */ -int pthread_key_create(pthread_key_t *key, void (*destructor)(void *)); +int +pthread_key_create(pthread_key_t *key, void (*destructor)(void *)); -int pthread_setspecific(pthread_key_t key, const void *value); +int +pthread_setspecific(pthread_key_t key, const void *value); -void *pthread_getspecific(pthread_key_t key); +void * +pthread_getspecific(pthread_key_t key); -int pthread_key_delete(pthread_key_t key); +int +pthread_key_delete(pthread_key_t key); #ifdef __cplusplus }