Skip to content

Commit 929d594

Browse files
authored
Add implementation for wasi_thread_spawn() (#1786)
For now this implementation uses thread manager. Not sure whether thread manager is needed in that case. In the future there'll be likely another syscall added (for pthread_exit) and for that we might need some kind of thread management - with that in mind, we keep thread manager for now and will refactor this later if needed.
1 parent 684ae65 commit 929d594

4 files changed

Lines changed: 166 additions & 11 deletions

File tree

build-scripts/runtime_lib.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ endif ()
127127
if (WAMR_BUILD_LIB_WASI_THREADS EQUAL 1)
128128
include (${IWASM_DIR}/libraries/lib-wasi-threads/lib_wasi_threads.cmake)
129129
# Enable the dependent feature if lib wasi threads is enabled
130+
set (WAMR_BUILD_THREAD_MGR 1)
130131
set (WAMR_BUILD_BULK_MEMORY 1)
131132
set (WAMR_BUILD_SHARED_MEMORY 1)
132133
endif ()

core/iwasm/common/wasm_native.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis);
5454
#endif
5555

5656
#if WASM_ENABLE_LIB_WASI_THREADS != 0
57+
bool
58+
lib_wasi_threads_init(void);
59+
60+
void
61+
lib_wasi_threads_destroy(void);
62+
5763
uint32
5864
get_lib_wasi_threads_export_apis(NativeSymbol **p_lib_wasi_threads_apis);
5965
#endif
@@ -444,6 +450,9 @@ wasm_native_init()
444450
#endif
445451

446452
#if WASM_ENABLE_LIB_WASI_THREADS != 0
453+
if (!lib_wasi_threads_init())
454+
goto fail;
455+
447456
n_native_symbols = get_lib_wasi_threads_export_apis(&native_symbols);
448457
if (n_native_symbols > 0
449458
&& !wasm_native_register_natives("wasi", native_symbols,
@@ -471,7 +480,7 @@ wasm_native_init()
471480
n_native_symbols = get_wasi_nn_export_apis(&native_symbols);
472481
if (!wasm_native_register_natives("wasi_nn", native_symbols,
473482
n_native_symbols))
474-
return false;
483+
goto fail;
475484
#endif
476485

477486
return true;
@@ -495,6 +504,10 @@ wasm_native_destroy()
495504
lib_pthread_destroy();
496505
#endif
497506

507+
#if WASM_ENABLE_LIB_WASI_THREADS != 0
508+
lib_wasi_threads_destroy();
509+
#endif
510+
498511
node = g_native_symbols_list;
499512
while (node) {
500513
node_next = node->next;

core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c

Lines changed: 139 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
44
*/
55

6+
#include "bh_log.h"
67
#include "wasmtime_ssp.h"
8+
#include "thread_manager.h"
79

810
#if WASM_ENABLE_INTERP != 0
911
#include "wasm_runtime.h"
@@ -13,10 +15,128 @@
1315
#include "aot_runtime.h"
1416
#endif
1517

16-
static __wasi_errno_t
17-
thread_spawn_wrapper(wasm_exec_env_t exec_env, void *start_arg)
18+
static const char *THREAD_START_FUNCTION = "wasi_thread_start";
19+
20+
static korp_mutex thread_id_lock;
21+
22+
typedef struct {
23+
/* app's entry function */
24+
wasm_function_inst_t start_func;
25+
/* arg of the app's entry function */
26+
uint32 arg;
27+
/* thread id passed to the app */
28+
int32 thread_id;
29+
} ThreadStartArg;
30+
31+
static int32
32+
allocate_thread_id()
33+
{
34+
static int32 thread_id = 0;
35+
36+
int32 id;
37+
38+
os_mutex_lock(&thread_id_lock);
39+
id = thread_id++;
40+
os_mutex_unlock(&thread_id_lock);
41+
return id;
42+
}
43+
44+
static void *
45+
thread_start(void *arg)
1846
{
19-
return __WASI_ENOSYS;
47+
wasm_exec_env_t exec_env = (wasm_exec_env_t)arg;
48+
wasm_module_inst_t module_inst = get_module_inst(exec_env);
49+
ThreadStartArg *thread_arg = exec_env->thread_arg;
50+
uint32 argv[2];
51+
52+
wasm_exec_env_set_thread_info(exec_env);
53+
argv[0] = thread_arg->thread_id;
54+
argv[1] = thread_arg->arg;
55+
56+
if (!wasm_runtime_call_wasm(exec_env, thread_arg->start_func, 2, argv)) {
57+
if (wasm_runtime_get_exception(module_inst))
58+
wasm_cluster_spread_exception(exec_env);
59+
}
60+
61+
/* routine exit, destroy instance */
62+
wasm_runtime_deinstantiate_internal(module_inst, true);
63+
64+
wasm_runtime_free(thread_arg);
65+
exec_env->thread_arg = NULL;
66+
67+
return NULL;
68+
}
69+
70+
static int32
71+
thread_spawn_wrapper(wasm_exec_env_t exec_env, uint32 start_arg)
72+
{
73+
wasm_module_t module = wasm_exec_env_get_module(exec_env);
74+
wasm_module_inst_t module_inst = get_module_inst(exec_env);
75+
wasm_module_inst_t new_module_inst = NULL;
76+
ThreadStartArg *thread_start_arg = NULL;
77+
wasm_function_inst_t start_func;
78+
int32 thread_id;
79+
uint32 stack_size = 8192;
80+
int32 ret = -1;
81+
#if WASM_ENABLE_LIBC_WASI != 0
82+
WASIContext *wasi_ctx;
83+
#endif
84+
85+
bh_assert(module);
86+
bh_assert(module_inst);
87+
88+
stack_size = ((WASMModuleInstance *)module_inst)->default_wasm_stack_size;
89+
90+
if (!(new_module_inst = wasm_runtime_instantiate_internal(
91+
module, true, stack_size, 0, NULL, 0)))
92+
return -1;
93+
94+
wasm_runtime_set_custom_data_internal(
95+
new_module_inst, wasm_runtime_get_custom_data(module_inst));
96+
97+
#if WASM_ENABLE_LIBC_WASI != 0
98+
wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst);
99+
if (wasi_ctx)
100+
wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx);
101+
#endif
102+
103+
start_func = wasm_runtime_lookup_function(new_module_inst,
104+
THREAD_START_FUNCTION, NULL);
105+
if (!start_func) {
106+
LOG_ERROR("Failed to find thread start function %s",
107+
THREAD_START_FUNCTION);
108+
goto thread_spawn_fail;
109+
}
110+
111+
if (!(thread_start_arg = wasm_runtime_malloc(sizeof(ThreadStartArg)))) {
112+
LOG_ERROR("Runtime args allocation failed");
113+
goto thread_spawn_fail;
114+
}
115+
116+
thread_start_arg->thread_id = thread_id = allocate_thread_id();
117+
thread_start_arg->arg = start_arg;
118+
thread_start_arg->start_func = start_func;
119+
120+
os_mutex_lock(&exec_env->wait_lock);
121+
ret = wasm_cluster_create_thread(exec_env, new_module_inst, thread_start,
122+
thread_start_arg);
123+
if (ret != 0) {
124+
os_mutex_unlock(&exec_env->wait_lock);
125+
LOG_ERROR("Failed to spawn a new thread");
126+
goto thread_spawn_fail;
127+
}
128+
os_mutex_unlock(&exec_env->wait_lock);
129+
130+
return thread_id;
131+
132+
thread_spawn_fail:
133+
if (new_module_inst)
134+
wasm_runtime_deinstantiate_internal(new_module_inst, true);
135+
136+
if (thread_start_arg)
137+
wasm_runtime_free(thread_start_arg);
138+
139+
return -1;
20140
}
21141

22142
/* clang-format off */
@@ -25,11 +145,26 @@ thread_spawn_wrapper(wasm_exec_env_t exec_env, void *start_arg)
25145
/* clang-format on */
26146

27147
static NativeSymbol native_symbols_lib_wasi_threads[] = { REG_NATIVE_FUNC(
28-
thread_spawn, "(*)i") };
148+
thread_spawn, "(i)i") };
29149

30150
uint32
31151
get_lib_wasi_threads_export_apis(NativeSymbol **p_lib_wasi_threads_apis)
32152
{
33153
*p_lib_wasi_threads_apis = native_symbols_lib_wasi_threads;
34154
return sizeof(native_symbols_lib_wasi_threads) / sizeof(NativeSymbol);
35155
}
156+
157+
bool
158+
lib_wasi_threads_init(void)
159+
{
160+
if (0 != os_mutex_init(&thread_id_lock))
161+
return false;
162+
163+
return true;
164+
}
165+
166+
void
167+
lib_wasi_threads_destroy(void)
168+
{
169+
os_mutex_destroy(&thread_id_lock);
170+
}

samples/wasi-threads/wasm-apps/no_pthread.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88

99
#include <stdlib.h>
1010
#include <stdio.h>
11+
#include <assert.h>
1112
#include <wasi/api.h>
1213

1314
static const int64_t SECOND = 1000 * 1000 * 1000;
1415

1516
typedef struct {
1617
int th_ready;
1718
int value;
19+
int thread_id;
1820
} shared_t;
1921

2022
__attribute__((export_name("wasi_thread_start"))) void
@@ -25,6 +27,7 @@ wasi_thread_start(int thread_id, int *start_arg)
2527
printf("New thread ID: %d, starting parameter: %d\n", thread_id,
2628
data->value);
2729

30+
data->thread_id = thread_id;
2831
data->value += 8;
2932
printf("Updated value: %d\n", data->value);
3033

@@ -35,12 +38,12 @@ wasi_thread_start(int thread_id, int *start_arg)
3538
int
3639
main(int argc, char **argv)
3740
{
38-
shared_t data = { 0, 52 };
39-
__wasi_errno_t err;
41+
shared_t data = { 0, 52, -1 };
42+
int thread_id;
4043

41-
err = __wasi_thread_spawn(&data);
42-
if (err != __WASI_ERRNO_SUCCESS) {
43-
printf("Failed to create thread: %d\n", err);
44+
thread_id = __wasi_thread_spawn(&data);
45+
if (thread_id < 0) {
46+
printf("Failed to create thread: %d\n", thread_id);
4447
return EXIT_FAILURE;
4548
}
4649

@@ -49,7 +52,10 @@ main(int argc, char **argv)
4952
return EXIT_FAILURE;
5053
}
5154

52-
printf("Thread completed, new value: %d\n", data.value);
55+
printf("Thread completed, new value: %d, thread id: %d\n", data.value,
56+
data.thread_id);
57+
58+
assert(thread_id == data.thread_id);
5359

5460
return EXIT_SUCCESS;
5561
}

0 commit comments

Comments
 (0)