diff --git a/.github/workflows/compilation_on_android_ubuntu.yml b/.github/workflows/compilation_on_android_ubuntu.yml index 6654e1b31..062b17297 100644 --- a/.github/workflows/compilation_on_android_ubuntu.yml +++ b/.github/workflows/compilation_on_android_ubuntu.yml @@ -368,9 +368,9 @@ jobs: mkdir wasi-libc cd wasi-libc git init - # "Rename thread_spawn import" commit on main branch + # "Fix a_store operation in atomic.h" commit on main branch git fetch https://github.com/WebAssembly/wasi-libc \ - 8f5275796a82f8ecfd0833a4f3f444fa37ed4546 + 1dfe5c302d1c5ab621f7abf04620fae92700fd22 git checkout FETCH_HEAD make -j \ AR=/opt/wasi-sdk/bin/llvm-ar \ @@ -532,9 +532,9 @@ jobs: mkdir wasi-libc cd wasi-libc git init - # "Rename thread_spawn import" commit on main branch + # "Fix a_store operation in atomic.h" commit on main branch git fetch https://github.com/WebAssembly/wasi-libc \ - 8f5275796a82f8ecfd0833a4f3f444fa37ed4546 + 1dfe5c302d1c5ab621f7abf04620fae92700fd22 git checkout FETCH_HEAD make -j \ AR=/opt/wasi-sdk/bin/llvm-ar \ diff --git a/.github/workflows/compilation_on_sgx.yml b/.github/workflows/compilation_on_sgx.yml index 2988a6fe1..a26f27aaf 100644 --- a/.github/workflows/compilation_on_sgx.yml +++ b/.github/workflows/compilation_on_sgx.yml @@ -265,9 +265,9 @@ jobs: mkdir wasi-libc cd wasi-libc git init - # "Rename thread_spawn import" commit on main branch + # "Fix a_store operation in atomic.h" commit on main branch git fetch https://github.com/WebAssembly/wasi-libc \ - 8f5275796a82f8ecfd0833a4f3f444fa37ed4546 + 1dfe5c302d1c5ab621f7abf04620fae92700fd22 git checkout FETCH_HEAD make \ AR=/opt/wasi-sdk/bin/llvm-ar \ diff --git a/core/iwasm/libraries/lib-wasi-threads/test/common.h b/core/iwasm/libraries/lib-wasi-threads/test/common.h index d032f824c..01ca932c5 100644 --- a/core/iwasm/libraries/lib-wasi-threads/test/common.h +++ b/core/iwasm/libraries/lib-wasi-threads/test/common.h @@ -6,11 +6,16 @@ #include #include #include -#include #include #include #include +#if USE_CUSTOM_SYNC_PRIMITIVES != 0 +#include "sync_primitives.h" +#else +#include +#endif + #include "wasi_thread_start.h" typedef enum { diff --git a/core/iwasm/libraries/lib-wasi-threads/test/global_lock.c b/core/iwasm/libraries/lib-wasi-threads/test/global_lock.c index 282bec71c..f81fca49b 100644 --- a/core/iwasm/libraries/lib-wasi-threads/test/global_lock.c +++ b/core/iwasm/libraries/lib-wasi-threads/test/global_lock.c @@ -11,7 +11,12 @@ #include #include #include + +#if USE_CUSTOM_SYNC_PRIMITIVES != 0 +#include "sync_primitives.h" +#else #include +#endif #include "wasi_thread_start.h" diff --git a/core/iwasm/libraries/lib-wasi-threads/test/sync_primitives.h b/core/iwasm/libraries/lib-wasi-threads/test/sync_primitives.h new file mode 100644 index 000000000..4b7dac8ec --- /dev/null +++ b/core/iwasm/libraries/lib-wasi-threads/test/sync_primitives.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include + +/* Mutex */ + +typedef int pthread_mutex_t; + +int +pthread_mutex_init(pthread_mutex_t *mutex, void *unused) +{ + *mutex = 0; + return 0; +} + +int +pthread_mutex_destroy(pthread_mutex_t *mutex) +{ + return 0; +} + +static bool +try_pthread_mutex_lock(pthread_mutex_t *mutex) +{ + int expected = 0; + return __atomic_compare_exchange_n(mutex, &expected, 1, false, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); +} + +int +pthread_mutex_lock(pthread_mutex_t *mutex) +{ + while (!try_pthread_mutex_lock(mutex)) + __builtin_wasm_memory_atomic_wait32(mutex, 1, -1); + return 0; +} + +int +pthread_mutex_unlock(pthread_mutex_t *mutex) +{ + __atomic_store_n(mutex, 0, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(mutex, 1); + return 0; +} + +/* Barrier */ + +typedef struct { + int count; + int num_threads; + int mutex; + int ready; +} pthread_barrier_t; + +int +pthread_barrier_init(pthread_barrier_t *barrier, void *unused, int num_threads) +{ + barrier->count = 0; + barrier->num_threads = num_threads; + barrier->ready = 0; + pthread_mutex_init(&barrier->mutex, NULL); + + return 0; +} + +int +pthread_barrier_wait(pthread_barrier_t *barrier) +{ + bool no_wait = false; + int count; + + pthread_mutex_lock(&barrier->mutex); + count = barrier->count++; + if (barrier->count >= barrier->num_threads) { + no_wait = true; + barrier->count = 0; + } + pthread_mutex_unlock(&barrier->mutex); + + if (no_wait) { + __atomic_store_n(&barrier->ready, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&barrier->ready, count); + return 0; + } + + __builtin_wasm_memory_atomic_wait32(&barrier->ready, 0, -1); + return 0; +} \ No newline at end of file diff --git a/samples/wasi-threads/README.md b/samples/wasi-threads/README.md index a5e1aed3c..a79a3cd6a 100644 --- a/samples/wasi-threads/README.md +++ b/samples/wasi-threads/README.md @@ -11,8 +11,6 @@ $ cmake .. $ make ... $ ./iwasm wasm-apps/no_pthread.wasm -... -$ ./iwasm wasm-apps/exception_propagation.wasm ``` ## Run samples in AOT mode diff --git a/samples/wasi-threads/wasm-apps/CMakeLists.txt b/samples/wasi-threads/wasm-apps/CMakeLists.txt index a6b288449..87f21e9fd 100644 --- a/samples/wasi-threads/wasm-apps/CMakeLists.txt +++ b/samples/wasi-threads/wasm-apps/CMakeLists.txt @@ -43,5 +43,4 @@ function (compile_sample SOURCE_FILE) ) endfunction () -compile_sample(no_pthread.c wasi_thread_start.S) -compile_sample(thread_termination.c wasi_thread_start.S) +compile_sample(no_pthread.c wasi_thread_start.S) \ No newline at end of file diff --git a/samples/wasi-threads/wasm-apps/thread_termination.c b/samples/wasi-threads/wasm-apps/thread_termination.c deleted file mode 100644 index 9f5cf1fe8..000000000 --- a/samples/wasi-threads/wasm-apps/thread_termination.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ -#ifndef __wasi__ -#error This example only compiles to WASM/WASI target -#endif - -#include -#include -#include -#include -#include -#include - -#include "wasi_thread_start.h" - -#define BUSY_WAIT 0 -#define ATOMIC_WAIT 1 -#define POLL_ONEOFF 2 - -/* Change parameters here to modify the sample behavior */ -#define TEST_TERMINATION_BY_TRAP 0 /* Otherwise `proc_exit` termination */ -#define TEST_TERMINATION_IN_MAIN_THREAD 1 /* Otherwise in spawn thread */ -#define LONG_TASK_IMPL ATOMIC_WAIT - -#define TIMEOUT_SECONDS 10 -#define NUM_THREADS 3 -static pthread_barrier_t barrier; - -typedef struct { - start_args_t base; - bool throw_exception; -} shared_t; - -void -run_long_task() -{ -#if LONG_TASK_IMPL == BUSY_WAIT - for (int i = 0; i < TIMEOUT_SECONDS; i++) - sleep(1); -#elif LONG_TASK_IMPL == ATOMIC_WAIT - __builtin_wasm_memory_atomic_wait32(0, 0, -1); -#else - sleep(TIMEOUT_SECONDS); -#endif -} - -void -start_job() -{ - /* Wait for all threads (including the main thread) to be ready */ - pthread_barrier_wait(&barrier); - run_long_task(); /* Task to be interrupted */ - assert(false && "Thread termination test failed"); -} - -void -terminate_process() -{ - /* Wait for all other threads (including main thread) to be ready */ - printf("Waiting before terminating\n"); - pthread_barrier_wait(&barrier); - - printf("Force termination\n"); -#if TEST_TERMINATION_BY_TRAP == 1 - __builtin_trap(); -#else - __wasi_proc_exit(33); -#endif -} - -void -__wasi_thread_start_C(int thread_id, int *start_arg) -{ - shared_t *data = (shared_t *)start_arg; - - if (data->throw_exception) { - terminate_process(); - } - else { - printf("Thread running\n"); - - start_job(); - } -} - -int -main(int argc, char **argv) -{ - int thread_id = -1, i; - shared_t data[NUM_THREADS] = { 0 }; - - if (pthread_barrier_init(&barrier, NULL, NUM_THREADS + 1) != 0) { - printf("Failed to init barrier\n"); - return EXIT_FAILURE; - } - - for (i = 0; i < NUM_THREADS; i++) { - /* No graceful memory free to simplify the example */ - if (!start_args_init(&data[i].base)) { - printf("Failed to allocate thread's stack\n"); - return EXIT_FAILURE; - } - } - - /* Create a thread that forces termination through trap or `proc_exit` */ -#if TEST_TERMINATION_IN_MAIN_THREAD == 1 - data[0].throw_exception = false; -#else - data[0].throw_exception = true; -#endif - thread_id = __wasi_thread_spawn(&data[0]); - if (thread_id < 0) { - printf("Failed to create thread: %d\n", thread_id); - return EXIT_FAILURE; - } - - /* Create two additional threads to test exception propagation */ - data[1].throw_exception = false; - thread_id = __wasi_thread_spawn(&data[1]); - if (thread_id < 0) { - printf("Failed to create thread: %d\n", thread_id); - return EXIT_FAILURE; - } - data[2].throw_exception = false; - thread_id = __wasi_thread_spawn(&data[2]); - if (thread_id < 0) { - printf("Failed to create thread: %d\n", thread_id); - return EXIT_FAILURE; - } - -#if TEST_TERMINATION_IN_MAIN_THREAD == 1 - printf("Force termination (main thread)\n"); - terminate_process(); -#else /* TEST_TERMINATION_IN_MAIN_THREAD */ - printf("Main thread running\n"); - - start_job(); -#endif /* TEST_TERMINATION_IN_MAIN_THREAD */ - return EXIT_SUCCESS; -}