Просмотр исходного кода

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
Xu Jun 4 лет назад
Родитель
Сommit
90a0057d33

+ 19 - 0
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"),

+ 11 - 0
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)
 {

+ 10 - 0
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                 *

+ 13 - 0
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)
 {

+ 18 - 0
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

+ 11 - 0
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 */

+ 43 - 21
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
 }