Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion test/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ for input in testsuite/*.c; do

if [ "$input" -nt "$output" ]; then
echo "Compiling $input"
$CC "$input" -o "$output"
$CC "$input" testsuite/wasi_thread_spawn.S -o "$output"
fi
done
41 changes: 25 additions & 16 deletions test/testsuite/thread_spawn-simple.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#include <assert.h>
#include <stdlib.h>
#include <wasi/api.h>

static const int64_t SECOND = 1000 * 1000 * 1000;

typedef struct {
typedef struct
{
char *stack;
int th_ready;
int th_continue;
int th_done;
Expand All @@ -12,16 +15,16 @@ typedef struct {
int value;
} shared_t;

__attribute__((export_name("wasi_thread_start"))) void
wasi_thread_start(int thread_id, int *start_arg)
void __wasi_thread_start_C(int thread_id, int *start_arg)
{
shared_t *data = (shared_t *)start_arg;

data->th_ready = 1;
__builtin_wasm_memory_atomic_notify(&data->th_ready, 1);

// so we can have all the threads alive at the same time
if (__builtin_wasm_memory_atomic_wait32(&data->th_continue, 0, SECOND) == 2) {
if (__builtin_wasm_memory_atomic_wait32(&data->th_continue, 0, SECOND) == 2)
{
data->failed = 1;
return;
}
Expand All @@ -35,36 +38,42 @@ wasi_thread_start(int thread_id, int *start_arg)
__builtin_wasm_memory_atomic_notify(&data->th_done, 1);
}

int
main(int argc, char **argv)
int main(int argc, char **argv)
{
shared_t data[3] = { 0 };
shared_t data[3] = {0};
int tid[3];
int data_count = sizeof(data) / sizeof(data[0]);
int i, j;

for (i = 0; i < data_count; i++) {
for (i = 0; i < data_count; i++)
{
data[i].stack = malloc(128);
data[i].value = 52;
assert(__wasi_thread_spawn(&data[i]) == 0);
tid[i] = __wasi_thread_spawn(&data[i]);
assert(tid[i] > 0);
assert(__builtin_wasm_memory_atomic_wait32(&data[i].th_ready, 0,
SECOND)
!= 2); // not a timeout
SECOND) != 2); // not a timeout
}

for (i = 0; i < data_count; i++) {
for (i = 0; i < data_count; i++)
{
__builtin_wasm_memory_atomic_notify(&data[i].th_continue, 1);
}

for (i = 0; i < data_count; i++) {
for (i = 0; i < data_count; i++)
{
assert(__builtin_wasm_memory_atomic_wait32(&data[i].th_done, 0,
SECOND)
!= 2); // not a timeout
SECOND) != 2); // not a timeout
assert(data[i].tid == tid[i]);
assert(data[i].value == 60);

for (j = i + 1; j < data_count; j++) {
for (j = i + 1; j < data_count; j++)
{
assert(data[i].tid != data[j].tid);
}

assert(data[i].failed == 0);
free(data[i].stack);
}

return 0;
Expand Down
28 changes: 28 additions & 0 deletions test/testsuite/wasi_thread_spawn.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# A copy of the wasi-libc implementation:
# https://github.com/WebAssembly/wasi-libc/blob/main/libc-top-half/musl/src/thread/wasm32/wasi_thread_start.s
.text

.export_name wasi_thread_start, wasi_thread_start

.globaltype __stack_pointer, i32
.functype __wasi_thread_start_C (i32, i32) -> ()

.hidden wasi_thread_start
.globl wasi_thread_start
.type wasi_thread_start,@function

wasi_thread_start:
.functype wasi_thread_start (i32, i32) -> ()

# Set up the minimum C environment.
# Note: offsetof(start_arg, stack) == 0
local.get 1 # start_arg
i32.load 0 # stack
global.set __stack_pointer

# Make the C function do the rest of work.
local.get 0 # tid
local.get 1 # start_arg
call __wasi_thread_start_C

end_function