From f13cfcf5f47fd26d5cb9d8f146b8080b6b09b443 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 16 Oct 2024 13:32:15 -0700 Subject: [PATCH 1/4] Cleanup wasm worker tests. NFC (#22749) - Use `emscripten_out` helper instead of EM_ASM(out(...)). - Remove tabs - Curly braces on the same line as keyword - Parameterize one test --- test/test_browser.py | 10 ++-- test/wasm_worker/c11__Thread_local.c | 9 ++-- test/wasm_worker/cancel_all_wait_asyncs.c | 9 ++-- .../cancel_all_wait_asyncs_at_address.c | 9 ++-- test/wasm_worker/cancel_wait_async.c | 9 ++-- test/wasm_worker/gcc___Thread.c | 9 ++-- .../hardware_concurrency_is_lock_free.c | 9 ++-- test/wasm_worker/hello_wasm_worker.c | 6 +-- test/wasm_worker/lock_async_acquire.c | 52 ++++++++----------- test/wasm_worker/lock_busyspin_wait_acquire.c | 27 ++++++---- .../lock_busyspin_waitinf_acquire.c | 9 ++-- test/wasm_worker/lock_wait_acquire.c | 26 ++++++---- test/wasm_worker/lock_wait_acquire2.c | 9 ++-- test/wasm_worker/lock_waitinf_acquire.c | 25 +++------ test/wasm_worker/malloc_wasm_worker.c | 14 +++-- test/wasm_worker/no_proxied_js_functions.c | 12 ++--- test/wasm_worker/post_function.c | 30 ++++------- .../post_function_to_main_thread.c | 9 ++-- test/wasm_worker/proxied_function.c | 13 +++-- test/wasm_worker/semaphore_try_acquire.c | 3 +- test/wasm_worker/semaphore_waitinf_acquire.c | 12 ++--- test/wasm_worker/terminate_all_wasm_workers.c | 24 +++------ test/wasm_worker/terminate_wasm_worker.c | 24 +++------ test/wasm_worker/thread_stack.c | 31 ++++++----- test/wasm_worker/wasm_worker_and_pthread.c | 9 ++-- test/wasm_worker/wasm_worker_code_size.c | 6 +-- test/wasm_worker/wasm_worker_self_id.c | 39 +++++++------- test/wasm_worker/wasm_worker_sleep.c | 18 +++---- .../wasm_worker_tls_wasm_assembly.c | 37 ++++++------- 29 files changed, 207 insertions(+), 292 deletions(-) diff --git a/test/test_browser.py b/test/test_browser.py index b89def707d33..73e62d846be0 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5011,9 +5011,13 @@ def test_wasm_worker_futex_wait(self, args): # Tests Wasm Worker thread stack setup @also_with_minimal_runtime - def test_wasm_worker_thread_stack(self): - for mode in (0, 1, 2): - self.btest('wasm_worker/thread_stack.c', expected='0', args=['-sWASM_WORKERS', f'-sSTACK_OVERFLOW_CHECK={mode}']) + @parameterized({ + '0': (0,), + '1': (1,), + '2': (2,), + }) + def test_wasm_worker_thread_stack(self, mode): + self.btest('wasm_worker/thread_stack.c', expected='0', args=['-sWASM_WORKERS', f'-sSTACK_OVERFLOW_CHECK={mode}']) # Tests emscripten_malloc_wasm_worker() and emscripten_current_thread_is_wasm_worker() functions @also_with_minimal_runtime diff --git a/test/wasm_worker/c11__Thread_local.c b/test/wasm_worker/c11__Thread_local.c index 52a9d8c6c77a..4e11bf231dcc 100644 --- a/test/wasm_worker/c11__Thread_local.c +++ b/test/wasm_worker/c11__Thread_local.c @@ -5,8 +5,7 @@ _Thread_local int __attribute__((aligned(64))) tls = 1; -void main_thread_func() -{ +void main_thread_func() { assert(!emscripten_current_thread_is_wasm_worker()); EM_ASM(out($0), tls); #ifdef REPORT_RESULT @@ -14,8 +13,7 @@ void main_thread_func() #endif } -void worker_main() -{ +void worker_main() { assert(emscripten_current_thread_is_wasm_worker()); assert(((intptr_t)&tls % 64) == 0); assert(tls != 42); @@ -27,8 +25,7 @@ void worker_main() char stack[1024]; -int main() -{ +int main() { EM_ASM(out($0), tls); assert(((intptr_t)&tls % 64) == 0); assert(!emscripten_current_thread_is_wasm_worker()); diff --git a/test/wasm_worker/cancel_all_wait_asyncs.c b/test/wasm_worker/cancel_all_wait_asyncs.c index 71d36a4de92f..3e103bd2b794 100644 --- a/test/wasm_worker/cancel_all_wait_asyncs.c +++ b/test/wasm_worker/cancel_all_wait_asyncs.c @@ -9,23 +9,20 @@ volatile int32_t addr = 1; bool testSucceeded = 1; -void asyncWaitFinishedShouldNotBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) -{ +void asyncWaitFinishedShouldNotBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) { emscripten_console_log("asyncWaitFinishedShouldNotBeCalled"); testSucceeded = 0; assert(0); // We should not reach here } -void asyncWaitFinishedShouldBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) -{ +void asyncWaitFinishedShouldBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) { emscripten_console_log("asyncWaitFinishedShouldBeCalled"); #ifdef REPORT_RESULT REPORT_RESULT(testSucceeded); #endif } -int main() -{ +int main() { emscripten_console_log("Async waiting on address should give a wait token"); ATOMICS_WAIT_TOKEN_T ret = emscripten_atomic_wait_async((int32_t*)&addr, 1, asyncWaitFinishedShouldNotBeCalled, (void*)42, EMSCRIPTEN_WAIT_ASYNC_INFINITY); assert(EMSCRIPTEN_IS_VALID_WAIT_TOKEN(ret)); diff --git a/test/wasm_worker/cancel_all_wait_asyncs_at_address.c b/test/wasm_worker/cancel_all_wait_asyncs_at_address.c index b51f3b8a011f..7f09ab896cf4 100644 --- a/test/wasm_worker/cancel_all_wait_asyncs_at_address.c +++ b/test/wasm_worker/cancel_all_wait_asyncs_at_address.c @@ -9,23 +9,20 @@ volatile int32_t addr = 1; bool testSucceeded = 1; -void asyncWaitFinishedShouldNotBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) -{ +void asyncWaitFinishedShouldNotBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) { emscripten_console_log("asyncWaitFinishedShouldNotBeCalled"); testSucceeded = 0; assert(0); // We should not reach here } -void asyncWaitFinishedShouldBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) -{ +void asyncWaitFinishedShouldBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) { emscripten_console_log("asyncWaitFinishedShouldBeCalled"); #ifdef REPORT_RESULT REPORT_RESULT(testSucceeded); #endif } -int main() -{ +int main() { emscripten_console_log("Async waiting on address should give a wait token"); ATOMICS_WAIT_TOKEN_T ret = emscripten_atomic_wait_async((int32_t*)&addr, 1, asyncWaitFinishedShouldNotBeCalled, (void*)42, EMSCRIPTEN_WAIT_ASYNC_INFINITY); assert(EMSCRIPTEN_IS_VALID_WAIT_TOKEN(ret)); diff --git a/test/wasm_worker/cancel_wait_async.c b/test/wasm_worker/cancel_wait_async.c index e4f0d8f8223e..2b15468712e4 100644 --- a/test/wasm_worker/cancel_wait_async.c +++ b/test/wasm_worker/cancel_wait_async.c @@ -9,23 +9,20 @@ volatile int32_t addr = 1; bool testSucceeded = 1; -void asyncWaitFinishedShouldNotBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) -{ +void asyncWaitFinishedShouldNotBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) { emscripten_console_log("asyncWaitFinishedShouldNotBeCalled"); testSucceeded = 0; assert(0); // We should not reach here } -void asyncWaitFinishedShouldBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) -{ +void asyncWaitFinishedShouldBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) { emscripten_console_log("asyncWaitFinishedShouldBeCalled"); #ifdef REPORT_RESULT REPORT_RESULT(testSucceeded); #endif } -int main() -{ +int main() { emscripten_console_log("Async waiting on address should give a wait token"); ATOMICS_WAIT_TOKEN_T ret = emscripten_atomic_wait_async((int32_t*)&addr, 1, asyncWaitFinishedShouldNotBeCalled, (void*)42, EMSCRIPTEN_WAIT_ASYNC_INFINITY); assert(EMSCRIPTEN_IS_VALID_WAIT_TOKEN(ret)); diff --git a/test/wasm_worker/gcc___Thread.c b/test/wasm_worker/gcc___Thread.c index 84c93ffd92ae..1d6e2a221216 100644 --- a/test/wasm_worker/gcc___Thread.c +++ b/test/wasm_worker/gcc___Thread.c @@ -5,8 +5,7 @@ __thread int tls = 1; -void main_thread_func() -{ +void main_thread_func() { assert(!emscripten_current_thread_is_wasm_worker()); EM_ASM(out($0), tls); #ifdef REPORT_RESULT @@ -14,8 +13,7 @@ void main_thread_func() #endif } -void worker_main() -{ +void worker_main() { assert(emscripten_current_thread_is_wasm_worker()); assert(tls != 42); assert(tls != 0); @@ -26,8 +24,7 @@ void worker_main() char stack[1024]; -int main() -{ +int main() { EM_ASM(out($0), tls); assert(!emscripten_current_thread_is_wasm_worker()); tls = 42; diff --git a/test/wasm_worker/hardware_concurrency_is_lock_free.c b/test/wasm_worker/hardware_concurrency_is_lock_free.c index c7e47fcd61b4..f02b0c6718b5 100644 --- a/test/wasm_worker/hardware_concurrency_is_lock_free.c +++ b/test/wasm_worker/hardware_concurrency_is_lock_free.c @@ -4,8 +4,7 @@ // Test emscripten_navigator_hardware_concurrency() and emscripten_atomics_is_lock_free() functions -void test() -{ +void test() { // Assume that test suite does have navigator.hardwareConcurrency. assert(emscripten_navigator_hardware_concurrency() >= 2); assert(emscripten_atomics_is_lock_free(1)); @@ -17,8 +16,7 @@ void test() assert(!emscripten_atomics_is_lock_free(31)); } -void worker_main() -{ +void worker_main() { test(); #ifdef REPORT_RESULT REPORT_RESULT(0); @@ -27,8 +25,7 @@ void worker_main() char stack[1024]; -int main() -{ +int main() { test(); emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(stack, sizeof(stack)); emscripten_wasm_worker_post_function_v(worker, worker_main); diff --git a/test/wasm_worker/hello_wasm_worker.c b/test/wasm_worker/hello_wasm_worker.c index cae9ac83cabe..0bfcec6902af 100644 --- a/test/wasm_worker/hello_wasm_worker.c +++ b/test/wasm_worker/hello_wasm_worker.c @@ -5,16 +5,14 @@ // This is the code example in site/source/docs/api_reference/wasm_workers.rst -void run_in_worker() -{ +void run_in_worker() { emscripten_console_log("Hello from wasm worker!\n"); #ifdef REPORT_RESULT REPORT_RESULT(0); #endif } -int main() -{ +int main() { emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(/*stack size: */1024); assert(worker); emscripten_wasm_worker_post_function_v(worker, run_in_worker); diff --git a/test/wasm_worker/lock_async_acquire.c b/test/wasm_worker/lock_async_acquire.c index f27f52b26cff..71ff86492c2b 100644 --- a/test/wasm_worker/lock_async_acquire.c +++ b/test/wasm_worker/lock_async_acquire.c @@ -17,36 +17,32 @@ bool testFinished = false; int numTimesMainThreadAcquiredLock = 0; int numTimesWasmWorkerAcquiredLock = 0; -void work() -{ -// emscripten_console_log("work"); +void work() { + // emscripten_console_log("work"); volatile int x = sharedState0; volatile int y = sharedState1; assert(x == y+1 || y == x+1); - if (emscripten_current_thread_is_wasm_worker()) + if (emscripten_current_thread_is_wasm_worker()) { ++numTimesWasmWorkerAcquiredLock; - else + } else { ++numTimesMainThreadAcquiredLock; + } - if (x < y) - { + if (x < y) { x = y + 1; - if (emscripten_current_thread_is_wasm_worker()) + if (emscripten_current_thread_is_wasm_worker()) { emscripten_wasm_worker_sleep(/*nsecs=*/(rand()%100000)); + } sharedState0 = x; - } - else - { + } else { y = x + 1; if (emscripten_current_thread_is_wasm_worker()) emscripten_wasm_worker_sleep(/*nsecs=*/(rand()%100000)); sharedState1 = y; - if (y > 100 && numTimesMainThreadAcquiredLock && numTimesWasmWorkerAcquiredLock) - { - if (!testFinished) - { + if (y > 100 && numTimesMainThreadAcquiredLock && numTimesWasmWorkerAcquiredLock) { + if (!testFinished) { emscripten_console_log("test finished"); #ifdef REPORT_RESULT REPORT_RESULT(0); @@ -59,9 +55,8 @@ void work() void schedule_work(void *userData); -void lock_async_acquired(volatile void *addr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) -{ -// emscripten_console_log("async lock acquired"); +void lock_async_acquired(volatile void *addr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) { + // emscripten_console_log("async lock acquired"); assert(addr == &lock); assert(val == 0 || val == 1); assert(waitResult == ATOMICS_WAIT_OK); @@ -69,23 +64,20 @@ void lock_async_acquired(volatile void *addr, uint32_t val, ATOMICS_WAIT_RESULT_ work(); emscripten_lock_release(&lock); - if (!testFinished) + if (!testFinished) { emscripten_set_timeout(schedule_work, 10, 0); + } } -void schedule_work(void *userData) -{ - if (emscripten_current_thread_is_wasm_worker() && emscripten_random() > 0.5) - { +void schedule_work(void *userData) { + if (emscripten_current_thread_is_wasm_worker() && emscripten_random() > 0.5) { emscripten_lock_waitinf_acquire(&lock); -// emscripten_console_log("sync lock acquired"); + // emscripten_console_log("sync lock acquired"); work(); emscripten_lock_release(&lock); if (!testFinished) emscripten_set_timeout(schedule_work, 0, 0); - } - else - { + } else { emscripten_lock_async_acquire(&lock, lock_async_acquired, (void*)42, EMSCRIPTEN_WAIT_ASYNC_INFINITY); } } @@ -94,11 +86,9 @@ void start_worker(int arg) { schedule_work(0); } -int main() -{ +int main() { #define NUM_THREADS 10 - for(int i = 0; i < NUM_THREADS; ++i) - { + for (int i = 0; i < NUM_THREADS; ++i) { emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(1024); emscripten_wasm_worker_post_function_vi(worker, start_worker, 0); } diff --git a/test/wasm_worker/lock_busyspin_wait_acquire.c b/test/wasm_worker/lock_busyspin_wait_acquire.c index da33f68c66c8..165a4fdb6df6 100644 --- a/test/wasm_worker/lock_busyspin_wait_acquire.c +++ b/test/wasm_worker/lock_busyspin_wait_acquire.c @@ -8,31 +8,37 @@ emscripten_lock_t lock = EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER; -void test() -{ - bool success = emscripten_lock_busyspin_wait_acquire(&lock, 0); // Expect no contention on free lock. +void test() { + // Expect no contention on free lock. + bool success = emscripten_lock_busyspin_wait_acquire(&lock, 0); assert(success == true); double t0 = emscripten_performance_now(); - success = emscripten_lock_busyspin_wait_acquire(&lock, 0); // We already have the lock, and emscripten_lock is not recursive, so this should fail. + // We already have the lock, and emscripten_lock is not recursive, so this + // should fail. + success = emscripten_lock_busyspin_wait_acquire(&lock, 0); double t1 = emscripten_performance_now(); assert(!success); - assert(t1 - t0 < 25); // Shouldn't have taken too much time to try the lock. + // Shouldn't have taken too much time to try the lock. + assert(t1 - t0 < 25); success = emscripten_lock_try_acquire(&lock); assert(!success); // We already have the lock. t0 = emscripten_performance_now(); - success = emscripten_lock_busyspin_wait_acquire(&lock, 1000.0); // We already have the lock, and emscripten_lock is not recursive, so this should fail. + // We already have the lock, and emscripten_lock is not recursive, so this + // should fail. + success = emscripten_lock_busyspin_wait_acquire(&lock, 1000.0); t1 = emscripten_performance_now(); assert(!success); - assert(t1 - t0 >= 900); // We should have waited for the requested duration for the lock.. apply some slack since timing can have some noise. + // We should have waited for the requested duration for the lock.. apply some + // slack since timing can have some noise. + assert(t1 - t0 >= 900); emscripten_lock_release(&lock); } -void worker_main() -{ +void worker_main() { test(); #ifdef REPORT_RESULT REPORT_RESULT(0); @@ -41,8 +47,7 @@ void worker_main() char stack[1024]; -int main() -{ +int main() { test(); emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(stack, sizeof(stack)); diff --git a/test/wasm_worker/lock_busyspin_waitinf_acquire.c b/test/wasm_worker/lock_busyspin_waitinf_acquire.c index f58c2d6e93fa..8a42a168420e 100644 --- a/test/wasm_worker/lock_busyspin_waitinf_acquire.c +++ b/test/wasm_worker/lock_busyspin_waitinf_acquire.c @@ -10,8 +10,7 @@ emscripten_lock_t lock = EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER; volatile int sharedState = 0; -void worker_main() -{ +void worker_main() { emscripten_lock_busyspin_waitinf_acquire(&lock); emscripten_atomic_add_u32((void*)&sharedState, 1); #ifdef REPORT_RESULT @@ -21,14 +20,12 @@ void worker_main() char stack[1024]; -void releaseLock(void *userData) -{ +void releaseLock(void *userData) { emscripten_atomic_sub_u32((void*)&sharedState, 1); emscripten_lock_release(&lock); } -int main() -{ +int main() { // Acquire the lock at startup. emscripten_lock_busyspin_waitinf_acquire(&lock); emscripten_atomic_add_u32((void*)&sharedState, 1); diff --git a/test/wasm_worker/lock_wait_acquire.c b/test/wasm_worker/lock_wait_acquire.c index 73527ee64688..e85dc1ad435a 100644 --- a/test/wasm_worker/lock_wait_acquire.c +++ b/test/wasm_worker/lock_wait_acquire.c @@ -8,25 +8,32 @@ emscripten_lock_t lock = EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER; -void worker_main() -{ - bool success = emscripten_lock_wait_acquire(&lock, 0); // Expect no contention on free lock. +void worker_main() { + // Expect no contention on free lock. + bool success = emscripten_lock_wait_acquire(&lock, 0); assert(success == true); double t0 = emscripten_performance_now(); - success = emscripten_lock_wait_acquire(&lock, 0); // We already have the lock, and emscripten_lock is not recursive, so this should fail. + // We already have the lock, and emscripten_lock is not recursive, so this + // should fail. + success = emscripten_lock_wait_acquire(&lock, 0); double t1 = emscripten_performance_now(); assert(!success); - assert(t1 - t0 < 25); // Shouldn't have taken too much time to try the lock. + // Shouldn't have taken too much time to try the lock. + assert(t1 - t0 < 25); success = emscripten_lock_try_acquire(&lock); - assert(!success); // We already have the lock. + // We already have the lock. + assert(!success); t0 = emscripten_performance_now(); - success = emscripten_lock_wait_acquire(&lock, 1000 * 1000000ull); // We already have the lock, and emscripten_lock is not recursive, so this should fail. + // We already have the lock, and emscripten_lock is not recursive, so this + // should fail. + success = emscripten_lock_wait_acquire(&lock, 1000 * 1000000ull); t1 = emscripten_performance_now(); assert(!success); - assert(t1 - t0 >= 1000); // We should have waited for the requested duration for the lock. + // We should have waited for the requested duration for the lock. + assert(t1 - t0 >= 1000); emscripten_lock_release(&lock); @@ -40,8 +47,7 @@ void worker_main() char stack[1024]; -int main() -{ +int main() { emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(stack, sizeof(stack)); emscripten_wasm_worker_post_function_v(worker, worker_main); } diff --git a/test/wasm_worker/lock_wait_acquire2.c b/test/wasm_worker/lock_wait_acquire2.c index 13cd111f1ffd..3ece04398aa4 100644 --- a/test/wasm_worker/lock_wait_acquire2.c +++ b/test/wasm_worker/lock_wait_acquire2.c @@ -8,8 +8,7 @@ emscripten_lock_t lock = EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER; -void worker1_main() -{ +void worker1_main() { emscripten_console_log("worker1 main try_acquiring lock"); bool success = emscripten_lock_try_acquire(&lock); // Expect no contention on free lock. emscripten_console_log("worker1 try_acquire lock finished"); @@ -22,8 +21,7 @@ void worker1_main() emscripten_console_log("worker1 released lock"); } -void worker2_main() -{ +void worker2_main() { emscripten_console_log("worker2 main sleeping 500 msecs"); emscripten_wasm_worker_sleep(500 * 1000000ull); emscripten_console_log("worker2 slept 500 msecs, try_acquiring lock"); @@ -44,8 +42,7 @@ void worker2_main() char stack1[1024]; char stack2[1024]; -int main() -{ +int main() { emscripten_wasm_worker_t worker1 = emscripten_create_wasm_worker(stack1, sizeof(stack1)); emscripten_wasm_worker_t worker2 = emscripten_create_wasm_worker(stack2, sizeof(stack2)); emscripten_wasm_worker_post_function_v(worker1, worker1_main); diff --git a/test/wasm_worker/lock_waitinf_acquire.c b/test/wasm_worker/lock_waitinf_acquire.c index ebc5dd6816de..7c2c562d60c8 100644 --- a/test/wasm_worker/lock_waitinf_acquire.c +++ b/test/wasm_worker/lock_waitinf_acquire.c @@ -15,8 +15,7 @@ volatile int sharedState1 = 1; volatile int numWorkersAlive = 0; -void test_ended() -{ +void test_ended() { EM_ASM(out(`Worker ${$0} last thread to finish. Reporting test end with sharedState0=${$1}, sharedState1=${$2}`), emscripten_wasm_worker_self_id(), sharedState0, sharedState1); assert(sharedState0 == sharedState1 + 1 || sharedState1 == sharedState0 + 1); #ifdef REPORT_RESULT @@ -24,25 +23,20 @@ void test_ended() #endif } -void worker_main() -{ +void worker_main() { EM_ASM(out(`Worker ${$0} running...`), emscripten_wasm_worker_self_id()); // Create contention on the lock from each thread, and stress the shared state // in a racy way that would show a breakage if the lock is not watertight. - for(int i = 0; i < 1000; ++i) - { + for (int i = 0; i < 1000; ++i) { emscripten_lock_waitinf_acquire(&lock); volatile int x = sharedState0; volatile int y = sharedState1; assert(x == y+1 || y == x+1); - if (x < y) - { + if (x < y) { x = y + 1; emscripten_wasm_worker_sleep(/*nsecs=*/((uint64_t)(emscripten_math_random()*1000))); sharedState0 = x; - } - else - { + } else { y = x + 1; emscripten_wasm_worker_sleep(/*nsecs=*/((uint64_t)(emscripten_math_random()*1000))); sharedState1 = y; @@ -54,20 +48,17 @@ void worker_main() // Are we the last thread to finish? If so, test has ended. uint32_t v = emscripten_atomic_sub_u32((void*)&numWorkersAlive, 1); - if (v == 1) - { + if (v == 1) { test_ended(); } } -int main() -{ +int main() { emscripten_lock_init(&lock); #define NUM_THREADS 4 numWorkersAlive = NUM_THREADS; - for(int i = 0; i < NUM_THREADS; ++i) - { + for (int i = 0; i < NUM_THREADS; ++i) { emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(1024); emscripten_wasm_worker_post_function_v(worker, worker_main); } diff --git a/test/wasm_worker/malloc_wasm_worker.c b/test/wasm_worker/malloc_wasm_worker.c index 818e88804166..e9939699bd9f 100644 --- a/test/wasm_worker/malloc_wasm_worker.c +++ b/test/wasm_worker/malloc_wasm_worker.c @@ -5,8 +5,7 @@ // Test emscripten_malloc_wasm_worker() and emscripten_current_thread_is_wasm_worker() functions -void worker_main() -{ +void worker_main() { emscripten_out("Hello from wasm worker!"); assert(emscripten_current_thread_is_wasm_worker()); #ifdef REPORT_RESULT @@ -14,10 +13,9 @@ void worker_main() #endif } -int main() -{ - assert(!emscripten_current_thread_is_wasm_worker()); - emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(/*stack size: */1024); - assert(worker); - emscripten_wasm_worker_post_function_v(worker, worker_main); +int main() { + assert(!emscripten_current_thread_is_wasm_worker()); + emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(/*stack size: */1024); + assert(worker); + emscripten_wasm_worker_post_function_v(worker, worker_main); } diff --git a/test/wasm_worker/no_proxied_js_functions.c b/test/wasm_worker/no_proxied_js_functions.c index 180d9035a5dc..97b935140526 100644 --- a/test/wasm_worker/no_proxied_js_functions.c +++ b/test/wasm_worker/no_proxied_js_functions.c @@ -6,8 +6,7 @@ void proxied_js_function(void); -int should_throw(void(*func)()) -{ +int should_throw(void(*func)()) { int threw = EM_ASM_INT({ // Patch over assert() so that it does not abort execution on assert failure, but instead // throws a catchable exception. @@ -29,13 +28,11 @@ int should_throw(void(*func)()) return threw; } -void test() -{ +void test() { proxied_js_function(); } -void worker_main() -{ +void worker_main() { assert(should_throw(test)); #ifdef REPORT_RESULT REPORT_RESULT(0); @@ -44,8 +41,7 @@ void worker_main() char stack[1024]; -int main() -{ +int main() { proxied_js_function(); emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(stack, sizeof(stack)); emscripten_wasm_worker_post_function_v(worker, worker_main); diff --git a/test/wasm_worker/post_function.c b/test/wasm_worker/post_function.c index ec1a06a71593..8cd08cbbe404 100644 --- a/test/wasm_worker/post_function.c +++ b/test/wasm_worker/post_function.c @@ -7,29 +7,25 @@ volatile int success = 0; -void v() -{ +void v() { emscripten_console_log("v"); ++success; } -void vi(int i) -{ +void vi(int i) { emscripten_console_log("vi"); assert(i == 1); ++success; } -void vii(int i, int j) -{ +void vii(int i, int j) { emscripten_console_log("vii"); assert(i == 2); assert(j == 3); ++success; } -void viii(int i, int j, int k) -{ +void viii(int i, int j, int k) { emscripten_console_log("viii"); assert(i == 4); assert(j == 5); @@ -37,23 +33,20 @@ void viii(int i, int j, int k) ++success; } -void vd(double i) -{ +void vd(double i) { emscripten_console_log("vd"); assert(i == 1.5); ++success; } -void vdd(double i, double j) -{ +void vdd(double i, double j) { emscripten_console_log("vdd"); assert(i == 2.5); assert(j == 3.5); ++success; } -void vddd(double i, double j, double k) -{ +void vddd(double i, double j, double k) { emscripten_console_log("vddd"); assert(i == 4.5); assert(j == 5.5); @@ -61,8 +54,7 @@ void vddd(double i, double j, double k) ++success; } -void viiiiiidddddd(int a, int b, int c, int d, int e, int f, double g, double h, double i, double j, double k, double l) -{ +void viiiiiidddddd(int a, int b, int c, int d, int e, int f, double g, double h, double i, double j, double k, double l) { emscripten_console_log("viiiiiidddddd"); assert(a == 10); assert(b == 11); @@ -79,8 +71,7 @@ void viiiiiidddddd(int a, int b, int c, int d, int e, int f, double g, double h, ++success; } -void test_finished() -{ +void test_finished() { #ifdef REPORT_RESULT REPORT_RESULT(success); #endif @@ -88,8 +79,7 @@ void test_finished() char stack[1024]; -int main() -{ +int main() { assert(!emscripten_current_thread_is_wasm_worker()); emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(stack, sizeof(stack)); emscripten_wasm_worker_post_function_v(worker, v); diff --git a/test/wasm_worker/post_function_to_main_thread.c b/test/wasm_worker/post_function_to_main_thread.c index 1636ef3eba9e..edfe5e44525b 100644 --- a/test/wasm_worker/post_function_to_main_thread.c +++ b/test/wasm_worker/post_function_to_main_thread.c @@ -6,8 +6,7 @@ // Test emscripten_wasm_worker_post_function_*() API and EMSCRIPTEN_WASM_WORKER_ID_PARENT // to send a message back from Worker to its parent thread. -void test_success(int i, double d) -{ +void test_success(int i, double d) { emscripten_console_log("test_success"); assert(!emscripten_current_thread_is_wasm_worker()); assert(i == 10); @@ -17,8 +16,7 @@ void test_success(int i, double d) #endif } -void worker_main() -{ +void worker_main() { emscripten_console_log("worker_main"); assert(emscripten_current_thread_is_wasm_worker()); emscripten_wasm_worker_post_function_sig(EMSCRIPTEN_WASM_WORKER_ID_PARENT, test_success, "id", 10, 0.5); @@ -26,8 +24,7 @@ void worker_main() char stack[1024]; -int main() -{ +int main() { emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(stack, sizeof(stack)); emscripten_wasm_worker_post_function_v(worker, worker_main); } diff --git a/test/wasm_worker/proxied_function.c b/test/wasm_worker/proxied_function.c index ee37097a2f6e..79bc7e0ce6ad 100644 --- a/test/wasm_worker/proxied_function.c +++ b/test/wasm_worker/proxied_function.c @@ -6,13 +6,11 @@ void proxied_js_function(void); -void test_finished() -{ +void test_finished() { REPORT_RESULT(0); } -void run_in_worker() -{ +void run_in_worker() { int threw = EM_ASM_INT({ try { _proxied_js_function(); @@ -28,8 +26,9 @@ void run_in_worker() } } -int main() -{ +int main() { emscripten_wasm_worker_post_function_v(emscripten_malloc_wasm_worker(1024), run_in_worker); - proxied_js_function(); // Pin a dependency from C code to the JS function to avoid needing to mess with cmdline export directives + // Pin a dependency from C code to the JS function to avoid needing to mess + // with cmdline export directives + proxied_js_function(); } diff --git a/test/wasm_worker/semaphore_try_acquire.c b/test/wasm_worker/semaphore_try_acquire.c index f3d656e2dcc2..2cc69f3128bf 100644 --- a/test/wasm_worker/semaphore_try_acquire.c +++ b/test/wasm_worker/semaphore_try_acquire.c @@ -9,8 +9,7 @@ emscripten_semaphore_t unavailable = EMSCRIPTEN_SEMAPHORE_T_STATIC_INITIALIZER(0); emscripten_semaphore_t available = EMSCRIPTEN_SEMAPHORE_T_STATIC_INITIALIZER(1); -int main() -{ +int main() { emscripten_console_log("try_acquiring unavailable semaphore should fail"); int idx = emscripten_semaphore_try_acquire(&unavailable, 1); assert(idx == -1); diff --git a/test/wasm_worker/semaphore_waitinf_acquire.c b/test/wasm_worker/semaphore_waitinf_acquire.c index b7f04732ffdd..26b197e83d49 100644 --- a/test/wasm_worker/semaphore_waitinf_acquire.c +++ b/test/wasm_worker/semaphore_waitinf_acquire.c @@ -12,8 +12,7 @@ emscripten_semaphore_t threadsCompleted = EMSCRIPTEN_SEMAPHORE_T_STATIC_INITIALI int threadCounter = 0; -void worker_main() -{ +void worker_main() { emscripten_console_log("worker_main"); // Increment semaphore to mark that this thread is waiting for a signal from control thread to start. @@ -32,8 +31,7 @@ void worker_main() emscripten_semaphore_release(&threadsCompleted, 1); } -void control_thread() -{ +void control_thread() { // Wait until we have three threads available to start running. emscripten_console_log("control_thread: waiting for three threads to complete loading"); emscripten_semaphore_waitinf_acquire(&threadsWaiting, 3); @@ -69,16 +67,14 @@ void control_thread() #endif } -int main() -{ +int main() { emscripten_semaphore_init(&threadsWaiting, 0); emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(1024); emscripten_wasm_worker_post_function_v(worker, control_thread); #define NUM_THREADS 6 - for(int i = 0; i < NUM_THREADS; ++i) - { + for (int i = 0; i < NUM_THREADS; ++i) { emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(1024); emscripten_wasm_worker_post_function_v(worker, worker_main); } diff --git a/test/wasm_worker/terminate_all_wasm_workers.c b/test/wasm_worker/terminate_all_wasm_workers.c index 576d36812f9b..0afe657edaec 100644 --- a/test/wasm_worker/terminate_all_wasm_workers.c +++ b/test/wasm_worker/terminate_all_wasm_workers.c @@ -9,8 +9,7 @@ static volatile int worker_started = 0; -void this_function_should_not_be_called(void *userData) -{ +void this_function_should_not_be_called(void *userData) { worker_started = -1; emscripten_err("this_function_should_not_be_called"); #ifdef REPORT_RESULT @@ -18,10 +17,8 @@ void this_function_should_not_be_called(void *userData) #endif } -void test_passed(void *userData) -{ - if (worker_started == 2) - { +void test_passed(void *userData) { + if (worker_started == 2) { emscripten_err("test_passed"); #ifdef REPORT_RESULT REPORT_RESULT(0/*ok*/); @@ -29,8 +26,7 @@ void test_passed(void *userData) } } -void worker_main() -{ +void worker_main() { ++worker_started; emscripten_err("Hello from wasm worker!"); // Schedule a function to be called, that should never happen, since the Worker @@ -41,8 +37,7 @@ void worker_main() char stack1[1024]; char stack2[1024]; -int should_throw(void(*func)(emscripten_wasm_worker_t worker), emscripten_wasm_worker_t worker) -{ +int should_throw(void(*func)(emscripten_wasm_worker_t worker), emscripten_wasm_worker_t worker) { int threw = EM_ASM_INT({ try { dynCall('vi', $0, $1); @@ -58,21 +53,18 @@ int should_throw(void(*func)(emscripten_wasm_worker_t worker), emscripten_wasm_w emscripten_wasm_worker_t worker[2]; -void post_bad_function(emscripten_wasm_worker_t worker) -{ +void post_bad_function(emscripten_wasm_worker_t worker) { // Try to post a function to the worker, this should throw emscripten_wasm_worker_post_function_vi(worker, (void(*)(int))this_function_should_not_be_called, 0); } -void terminate_worker(void *userData) -{ +void terminate_worker(void *userData) { emscripten_terminate_all_wasm_workers(); assert(should_throw(post_bad_function, worker[0])); assert(should_throw(post_bad_function, worker[1])); } -int main() -{ +int main() { worker[0] = emscripten_create_wasm_worker(stack1, sizeof(stack1)); worker[1] = emscripten_create_wasm_worker(stack2, sizeof(stack2)); emscripten_wasm_worker_post_function_v(worker[0], worker_main); diff --git a/test/wasm_worker/terminate_wasm_worker.c b/test/wasm_worker/terminate_wasm_worker.c index d3dd554817f0..d2092c851a80 100644 --- a/test/wasm_worker/terminate_wasm_worker.c +++ b/test/wasm_worker/terminate_wasm_worker.c @@ -9,8 +9,7 @@ static volatile int worker_started = 0; -void this_function_should_not_be_called(void *userData) -{ +void this_function_should_not_be_called(void *userData) { worker_started = -1; emscripten_console_error("this_function_should_not_be_called"); #ifdef REPORT_RESULT @@ -18,10 +17,8 @@ void this_function_should_not_be_called(void *userData) #endif } -void test_passed(void *userData) -{ - if (worker_started == 1) - { +void test_passed(void *userData) { + if (worker_started == 1) { emscripten_console_error("test_passed"); #ifdef REPORT_RESULT REPORT_RESULT(0/*ok*/); @@ -29,8 +26,7 @@ void test_passed(void *userData) } } -void worker_main() -{ +void worker_main() { worker_started = 1; emscripten_console_error("Hello from wasm worker!"); // Schedule a function to be called, that should never happen, since the Worker @@ -40,8 +36,7 @@ void worker_main() char stack[1024]; -int should_throw(void(*func)()) -{ +int should_throw(void(*func)()) { int threw = EM_ASM_INT({ try { dynCall('v', Number($0)); @@ -57,20 +52,17 @@ int should_throw(void(*func)()) emscripten_wasm_worker_t worker = 0; -void post_bad_function() -{ +void post_bad_function() { // Try to post a function to the worker, this should throw emscripten_wasm_worker_post_function_vi(worker, (void(*)(int))this_function_should_not_be_called, 0); } -void terminate_worker(void *userData) -{ +void terminate_worker(void *userData) { emscripten_terminate_wasm_worker(worker); assert(should_throw(post_bad_function)); } -int main() -{ +int main() { worker = emscripten_create_wasm_worker(stack, sizeof(stack)); emscripten_wasm_worker_post_function_v(worker, worker_main); diff --git a/test/wasm_worker/thread_stack.c b/test/wasm_worker/thread_stack.c index b6c7ba913ddb..6d5435d6e0fd 100644 --- a/test/wasm_worker/thread_stack.c +++ b/test/wasm_worker/thread_stack.c @@ -1,43 +1,42 @@ -#include +#include #include #include #include #include #include -#define THREAD_STACK_SIZE 1024 +#define THREAD_STACK_SIZE 2048 #define NUM_THREADS 2 void *thread_stack[NUM_THREADS]; volatile int threadsOk = 0; -void test_stack(int i) -{ - EM_ASM(out(`In thread ${$0}, stack low addr=0x${$1.toString(16)}, emscripten_stack_get_base()=0x${$2.toString(16)}, emscripten_stack_get_end()=0x${$3.toString(16)}, THREAD_STACK_SIZE=0x${$4.toString(16)}`), - i, thread_stack[i], emscripten_stack_get_base(), emscripten_stack_get_end(), THREAD_STACK_SIZE); +void test_stack(int i) { + emscripten_outf("In thread %d, stack low addr=%p, emscripten_stack_get_base()=%p, emscripten_stack_get_end()=%p, THREAD_STACK_SIZE=%d", + i, thread_stack[i], + (void*)emscripten_stack_get_base(), + (void*)emscripten_stack_get_end(), + THREAD_STACK_SIZE); assert(emscripten_stack_get_base() == (uintptr_t)thread_stack[i] + THREAD_STACK_SIZE); assert(emscripten_stack_get_end() == (uintptr_t)thread_stack[i]); int ok = __sync_fetch_and_add(&threadsOk, 1); - EM_ASM(out($0), ok); - if (ok == 1) - { - EM_ASM(out(`Test finished!`)); + emscripten_outf("%d", ok); + if (ok == 1) { + emscripten_out("Test finished!"); #ifdef REPORT_RESULT REPORT_RESULT(0); #endif } } -int main() -{ - EM_ASM(out(`Main thread stack base=0x${$0.toString(16)}, end=0x${$1.toString(16)}`), emscripten_stack_get_base(), emscripten_stack_get_end()); +int main() { + emscripten_outf("Main thread stack base=%p, end=%p", (void*)emscripten_stack_get_base(), (void*)emscripten_stack_get_end()); - for(int i = 0; i < NUM_THREADS; ++i) - { + for (int i = 0; i < NUM_THREADS; ++i) { thread_stack[i] = memalign(16, THREAD_STACK_SIZE); emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(thread_stack[i], THREAD_STACK_SIZE); - EM_ASM(out(`Created thread ${$0} with stack ptr=0x${$1.toString(16)}, size=0x${$2.toString(16)}`), i, thread_stack[i], THREAD_STACK_SIZE); + emscripten_outf("Created thread %d with stack ptr=%p, size=%x", i, thread_stack[i], THREAD_STACK_SIZE); emscripten_wasm_worker_post_function_vi(worker, test_stack, i); } } diff --git a/test/wasm_worker/wasm_worker_and_pthread.c b/test/wasm_worker/wasm_worker_and_pthread.c index 1ea129f5df48..63afb9d5ef83 100644 --- a/test/wasm_worker/wasm_worker_and_pthread.c +++ b/test/wasm_worker/wasm_worker_and_pthread.c @@ -15,8 +15,7 @@ EM_JS(int, am_i_wasm_worker, (), { return ENVIRONMENT_IS_WASM_WORKER; }); -void *thread_main(void *arg) -{ +void *thread_main(void *arg) { emscripten_out("hello from pthread!"); assert(am_i_pthread()); assert(!am_i_wasm_worker()); @@ -26,8 +25,7 @@ void *thread_main(void *arg) return 0; } -void worker_main() -{ +void worker_main() { emscripten_out("hello from wasm worker!"); assert(!am_i_pthread()); assert(am_i_wasm_worker()); @@ -41,8 +39,7 @@ void worker_main() #endif } -int main() -{ +int main() { pthread_t thread; pthread_create(&thread, NULL, thread_main, NULL); diff --git a/test/wasm_worker/wasm_worker_code_size.c b/test/wasm_worker/wasm_worker_code_size.c index 9930298614c6..f491ff86aaab 100644 --- a/test/wasm_worker/wasm_worker_code_size.c +++ b/test/wasm_worker/wasm_worker_code_size.c @@ -7,12 +7,10 @@ EM_JS(void, hello, (void), { console.log("Hello from wasm worker!"); }); -void run_in_worker() -{ +void run_in_worker() { hello(); } -int main() -{ +int main() { emscripten_wasm_worker_post_function_v(emscripten_malloc_wasm_worker(1024), run_in_worker); } diff --git a/test/wasm_worker/wasm_worker_self_id.c b/test/wasm_worker/wasm_worker_self_id.c index 42ed57fce4f8..d846f9ee51f4 100644 --- a/test/wasm_worker/wasm_worker_self_id.c +++ b/test/wasm_worker/wasm_worker_self_id.c @@ -8,40 +8,37 @@ emscripten_wasm_worker_t worker2 = 0; int successes = 0; -void test_success() -{ +void test_success() { #ifdef REPORT_RESULT - if (__atomic_add_fetch(&successes, 1, __ATOMIC_SEQ_CST) == 2) - { - REPORT_RESULT(0); - } + if (__atomic_add_fetch(&successes, 1, __ATOMIC_SEQ_CST) == 2) { + REPORT_RESULT(0); + } #endif } -void worker1_main() -{ +void worker1_main() { assert(emscripten_wasm_worker_self_id() != 0); assert(emscripten_wasm_worker_self_id() == worker1); - if (emscripten_wasm_worker_self_id() == worker1) - test_success(); + if (emscripten_wasm_worker_self_id() == worker1) { + test_success(); + } } -void worker2_main() -{ +void worker2_main() { assert(emscripten_wasm_worker_self_id() != 0); assert(emscripten_wasm_worker_self_id() == worker2); - if (emscripten_wasm_worker_self_id() == worker2) - test_success(); + if (emscripten_wasm_worker_self_id() == worker2) { + test_success(); + } } char stack1[1024]; char stack2[1024]; -int main() -{ - assert(emscripten_wasm_worker_self_id() == 0); - worker1 = emscripten_create_wasm_worker(stack1, sizeof(stack1)); - worker2 = emscripten_create_wasm_worker(stack2, sizeof(stack2)); - emscripten_wasm_worker_post_function_v(worker1, worker1_main); - emscripten_wasm_worker_post_function_v(worker2, worker2_main); +int main() { + assert(emscripten_wasm_worker_self_id() == 0); + worker1 = emscripten_create_wasm_worker(stack1, sizeof(stack1)); + worker2 = emscripten_create_wasm_worker(stack2, sizeof(stack2)); + emscripten_wasm_worker_post_function_v(worker1, worker1_main); + emscripten_wasm_worker_post_function_v(worker2, worker2_main); } diff --git a/test/wasm_worker/wasm_worker_sleep.c b/test/wasm_worker/wasm_worker_sleep.c index e3b87d9421e1..e81dc56c45ee 100644 --- a/test/wasm_worker/wasm_worker_sleep.c +++ b/test/wasm_worker/wasm_worker_sleep.c @@ -1,20 +1,18 @@ #include #include -void worker_main() -{ - double t0 = emscripten_performance_now(); - emscripten_wasm_worker_sleep(/*nsecs=*/1500*1000000); - double t1 = emscripten_performance_now(); +void worker_main() { + double t0 = emscripten_performance_now(); + emscripten_wasm_worker_sleep(/*nsecs=*/1500*1000000); + double t1 = emscripten_performance_now(); #ifdef REPORT_RESULT - REPORT_RESULT(t1-t0 >= 1500); + REPORT_RESULT(t1-t0 >= 1500); #endif } char stack[1024]; -int main() -{ - emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(stack, sizeof(stack)); - emscripten_wasm_worker_post_function_v(worker, worker_main); +int main() { + emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(stack, sizeof(stack)); + emscripten_wasm_worker_post_function_v(worker, worker_main); } diff --git a/test/wasm_worker/wasm_worker_tls_wasm_assembly.c b/test/wasm_worker/wasm_worker_tls_wasm_assembly.c index fe72228a8c59..ad737f4f40c2 100644 --- a/test/wasm_worker/wasm_worker_tls_wasm_assembly.c +++ b/test/wasm_worker/wasm_worker_tls_wasm_assembly.c @@ -8,33 +8,30 @@ int globalData = 1; int get_tls_variable(void); void set_tls_variable(int var); -void main_thread_func() -{ - assert(!emscripten_current_thread_is_wasm_worker()); - assert(globalData == 3); +void main_thread_func() { + assert(!emscripten_current_thread_is_wasm_worker()); + assert(globalData == 3); #ifdef REPORT_RESULT - REPORT_RESULT(get_tls_variable()); + REPORT_RESULT(get_tls_variable()); #endif } -void worker_main() -{ - assert(emscripten_current_thread_is_wasm_worker()); - assert(get_tls_variable() == 0); - assert(globalData == 2); - globalData = 3; +void worker_main() { + assert(emscripten_current_thread_is_wasm_worker()); + assert(get_tls_variable() == 0); + assert(globalData == 2); + globalData = 3; set_tls_variable(123456); // Try to write garbage data to the memory location. - emscripten_wasm_worker_post_function_v(0, main_thread_func); + emscripten_wasm_worker_post_function_v(0, main_thread_func); } char stack[1024]; -int main() -{ - assert(!emscripten_current_thread_is_wasm_worker()); - assert(globalData == 1); - globalData = 2; - set_tls_variable(42); - emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(stack, sizeof(stack)); - emscripten_wasm_worker_post_function_v(worker, worker_main); +int main() { + assert(!emscripten_current_thread_is_wasm_worker()); + assert(globalData == 1); + globalData = 2; + set_tls_variable(42); + emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(stack, sizeof(stack)); + emscripten_wasm_worker_post_function_v(worker, worker_main); } From 18321c55274fdbbce6b0cf45ccf5e505ecea01b0 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Wed, 16 Oct 2024 13:39:33 -0700 Subject: [PATCH 2/4] Allow `SHARED_MEMORY` flag to be used independently. (#22683) Currently, there are a couple of restrictions on the `SHARED_MEMORY` flag: * Attempting to use the `SHARED_MEMORY` flag without the `PTHREADS` or `WASM_WORKERS` flags simply fails, because we don't have variations of the system libraries that have this flag standalone. Instead, emcc attempts to use the single-threaded system libraries, which are not compatible with the user's build because they don't have the correct wasm feature flags (i.e. -matomics and -mbulk-memory). This PR adds `SHARED_MEMORY`-only variations of the system libraries, which allows users to build with a standalone `SHARED_MEMORY` flag without error. * Currently, `SHARED_MEMORY` also implies `IMPORTED_MEMORY`. However, `IMPORTED_MEMORY` is only important for builds that use the `PTHREADS` or `WASM_WORKERS` flags, since they actually do multi-threading and need to read and write to the same memory across workers. This PR changes this so that if a standalone `SHARED_MEMORY` flag is specified, it can still avoid importing the memory. The use-case for enabling the `SHARED_MEMORY` flag without actually having an actual threading implementation is to be compatible with other modules which may import that memory whose import declaration specifies the memory as shared. This is an important use-case for Flutter, as we want to create two variations of the emscripten-generated module (one single-threaded and one multi-threaded, depending on whether the environment supports it) while keeping the module that imports the emscripten-generated module the same (which means keeping the memory import declaration as shared). --- system/lib/compiler-rt/stack_limits.S | 54 +--------------- system/lib/dlmalloc.c | 3 +- .../lib/wasm_worker/wasm_worker_initialize.S | 64 +++++++++++++++++++ test/core/test_dlfcn_self.exports | 2 + test/core/test_em_asm_unicode.out | 2 +- test/core/test_longjmp.out | 2 +- tools/link.py | 2 +- tools/system_libs.py | 21 +++++- 8 files changed, 91 insertions(+), 59 deletions(-) create mode 100644 system/lib/wasm_worker/wasm_worker_initialize.S diff --git a/system/lib/compiler-rt/stack_limits.S b/system/lib/compiler-rt/stack_limits.S index 1c4c719fa18a..d6906fe61ab7 100644 --- a/system/lib/compiler-rt/stack_limits.S +++ b/system/lib/compiler-rt/stack_limits.S @@ -15,6 +15,7 @@ #endif .globaltype __stack_pointer, PTR +.globl __stack_pointer .section .globals,"",@ @@ -22,7 +23,9 @@ # using PTR.const rather than using the `emscripten_stack_init` .globaltype __stack_end, PTR __stack_end: +.globl __stack_end .globaltype __stack_base, PTR +.globl __stack_base __stack_base: .section .text,"",@ @@ -82,57 +85,6 @@ emscripten_stack_get_free: PTR.sub end_function -#ifdef __EMSCRIPTEN_WASM_WORKERS__ -# TODO: Relocate the following to its own file wasm_worker.S, but need to figure out how to reference -# __stack_base and __stack_end globals from a separate file as externs in order for that to work. -.globl _emscripten_wasm_worker_initialize -_emscripten_wasm_worker_initialize: - .functype _emscripten_wasm_worker_initialize (PTR /*stackLowestAddress*/, i32 /*stackSize*/) -> () - - // __stack_end = stackLowestAddress + (__builtin_wasm_tls_size() + 15) & -16; - local.get 0 - .globaltype __tls_size, PTR, immutable - global.get __tls_size - PTR.add - PTR.const 0xf - PTR.add - PTR.const -0x10 - PTR.and - global.set __stack_end - - // __stack_base = stackLowestAddress + stackSize; - local.get 0 - local.get 1 -#ifdef __wasm64__ - i64.extend_i32_u -#endif - PTR.add - global.set __stack_base - -// TODO: We'd like to do this here to avoid JS side calls to __set_stack_limits. -// (or even better, we'd like to avoid duplicate versions of the stack variables) -// See https://github.com/emscripten-core/emscripten/issues/16496 -// global.get __stack_base -// global.get __stack_end -// .functype __set_stack_limits (PTR, PTR) -> () -// call __set_stack_limits - - // __wasm_init_tls(stackLowestAddress); - local.get 0 - .functype __wasm_init_tls (PTR) -> () - call __wasm_init_tls - - // N.b. The function __wasm_init_tls above does not need - // __stack_pointer initialized, and it destroys the value it was set to. - // So we must initialize __stack_pointer only *after* completing __wasm_init_tls: - - // __stack_pointer = __stack_base; - global.get __stack_base - global.set __stack_pointer - - end_function -#endif - # Add emscripten_stack_init to static ctors .section .init_array.1,"",@ .p2align ALIGN diff --git a/system/lib/dlmalloc.c b/system/lib/dlmalloc.c index 68fbe7f33275..f55ff649cfef 100644 --- a/system/lib/dlmalloc.c +++ b/system/lib/dlmalloc.c @@ -21,13 +21,12 @@ /* XXX Emscripten Tracing API. This defines away the code if tracing is disabled. */ #include -#ifdef __EMSCRIPTEN_WASM_WORKERS__ +#ifdef __EMSCRIPTEN_SHARED_MEMORY__ #define USE_LOCKS 1 #endif /* Make malloc() and free() threadsafe by securing the memory allocations with pthread mutexes. */ #if __EMSCRIPTEN_PTHREADS__ -#define USE_LOCKS 1 #define USE_SPIN_LOCKS 0 // Ensure we use pthread_mutex_t. #endif diff --git a/system/lib/wasm_worker/wasm_worker_initialize.S b/system/lib/wasm_worker/wasm_worker_initialize.S new file mode 100644 index 000000000000..8e144158a3f8 --- /dev/null +++ b/system/lib/wasm_worker/wasm_worker_initialize.S @@ -0,0 +1,64 @@ +.extern __stack_pointer +.extern __stack_base +.extern __stack_end + +#ifdef __wasm64__ +#define PTR i64 +#define ALIGN 3 +#define PTRSTORE .int64 +#else +#define PTR i32 +#define ALIGN 2 +#define PTRSTORE .int32 +#endif + +.globaltype __stack_pointer, PTR +.globaltype __stack_end, PTR +.globaltype __stack_base, PTR + +.globl _emscripten_wasm_worker_initialize +_emscripten_wasm_worker_initialize: + .functype _emscripten_wasm_worker_initialize (PTR /*stackLowestAddress*/, i32 /*stackSize*/) -> () + + // __stack_end = stackLowestAddress + (__builtin_wasm_tls_size() + 15) & -16; + local.get 0 + .globaltype __tls_size, PTR, immutable + global.get __tls_size + PTR.add + PTR.const 0xf + PTR.add + PTR.const -0x10 + PTR.and + global.set __stack_end + + // __stack_base = stackLowestAddress + stackSize; + local.get 0 + local.get 1 +#ifdef __wasm64__ + i64.extend_i32_u +#endif + PTR.add + global.set __stack_base + +// TODO: We'd like to do this here to avoid JS side calls to __set_stack_limits. +// (or even better, we'd like to avoid duplicate versions of the stack variables) +// See https://github.com/emscripten-core/emscripten/issues/16496 +// global.get __stack_base +// global.get __stack_end +// .functype __set_stack_limits (PTR, PTR) -> () +// call __set_stack_limits + + // __wasm_init_tls(stackLowestAddress); + local.get 0 + .functype __wasm_init_tls (PTR) -> () + call __wasm_init_tls + + // N.b. The function __wasm_init_tls above does not need + // __stack_pointer initialized, and it destroys the value it was set to. + // So we must initialize __stack_pointer only *after* completing __wasm_init_tls: + + // __stack_pointer = __stack_base; + global.get __stack_base + global.set __stack_pointer + + end_function diff --git a/test/core/test_dlfcn_self.exports b/test/core/test_dlfcn_self.exports index 778003379ab0..0017bb938a99 100644 --- a/test/core/test_dlfcn_self.exports +++ b/test/core/test_dlfcn_self.exports @@ -9,7 +9,9 @@ __progname_full __sig_actions __sig_pending __signgam +__stack_base __stack_chk_guard +__stack_end __threwValue __timezone __tzname diff --git a/test/core/test_em_asm_unicode.out b/test/core/test_em_asm_unicode.out index 4ef53eab9a77..31caff809046 100644 --- a/test/core/test_em_asm_unicode.out +++ b/test/core/test_em_asm_unicode.out @@ -1 +1 @@ -hello world… \ No newline at end of file +hello world… diff --git a/test/core/test_longjmp.out b/test/core/test_longjmp.out index 4a412fef09f7..e9cc75258d28 100644 --- a/test/core/test_longjmp.out +++ b/test/core/test_longjmp.out @@ -1,4 +1,4 @@ first result: 1 1 second -result: 2 -1 \ No newline at end of file +result: 2 -1 diff --git a/tools/link.py b/tools/link.py index 22a8b7494fb0..44fee4acef50 100644 --- a/tools/link.py +++ b/tools/link.py @@ -1413,7 +1413,7 @@ def phase_linker_setup(options, state, newargs): 'removeRunDependency', ] - if settings.SHARED_MEMORY or settings.RELOCATABLE or settings.ASYNCIFY_LAZY_LOAD_CODE: + if settings.PTHREADS or settings.WASM_WORKERS or settings.RELOCATABLE or settings.ASYNCIFY_LAZY_LOAD_CODE: settings.IMPORTED_MEMORY = 1 set_initial_memory() diff --git a/tools/system_libs.py b/tools/system_libs.py index c202d3770747..13413638054d 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -742,12 +742,17 @@ def vary_on(cls): @classmethod def get_default_variation(cls, **kwargs): - return super().get_default_variation(is_mt=settings.PTHREADS, is_ww=settings.WASM_WORKERS and not settings.PTHREADS, **kwargs) + return super().get_default_variation( + is_mt=settings.PTHREADS, + is_ww=settings.SHARED_MEMORY and not settings.PTHREADS, + **kwargs + ) @classmethod def variations(cls): combos = super(MTLibrary, cls).variations() - # To save on # of variations, pthreads and Wasm workers when used together, just use pthreads variation. + + # These are mutually exclusive, only one flag will be set at any give time. return [combo for combo in combos if not combo['is_mt'] or not combo['is_ww']] @@ -1452,9 +1457,19 @@ def get_default_variation(cls, **kwargs): return super().get_default_variation(stub=not settings.WASM_WORKERS, **kwargs) def get_files(self): + files = [] + if self.is_stub: + files = [ + 'library_wasm_worker_stub.c' + ] + else: + files = [ + 'library_wasm_worker.c', + 'wasm_worker_initialize.S', + ] return files_in_path( path='system/lib/wasm_worker', - filenames=['library_wasm_worker_stub.c' if self.is_stub else 'library_wasm_worker.c']) + filenames=files) def can_use(self): # see src/library_wasm_worker.js From a98af2b78c86f0c577ac09a57a6a5c7a26ef16ee Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 16 Oct 2024 14:26:51 -0700 Subject: [PATCH 3/4] Update SDL2 port to version that includes wasm64 fixes. (#22708) Also, fix a wasm64 bug GL emulation that was only exposed by running the tests which are no longer disabled. --- src/library_glemu.js | 11 +++++------ test/test_browser.py | 4 ---- tools/ports/sdl2.py | 10 +++++----- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/library_glemu.js b/src/library_glemu.js index 2ae83e8ac78b..196a889f0921 100644 --- a/src/library_glemu.js +++ b/src/library_glemu.js @@ -2047,7 +2047,7 @@ var LibraryGLEmulation = { GLImmediate.rendererComponents[name] = 1; #if ASSERTIONS if (GLImmediate.enabledClientAttributes[name]) { - out("Warning: glTexCoord used after EnableClientState for TEXTURE_COORD_ARRAY for TEXTURE0. Disabling TEXTURE_COORD_ARRAY..."); + warnOnce("Warning: glTexCoord used after EnableClientState for TEXTURE_COORD_ARRAY for TEXTURE0. Disabling TEXTURE_COORD_ARRAY..."); } #endif GLImmediate.enabledClientAttributes[name] = true; @@ -2980,11 +2980,10 @@ var LibraryGLEmulation = { var attr = attributes[i]; var srcStride = Math.max(attr.sizeBytes, attr.stride); if ((srcStride & 3) == 0 && (attr.sizeBytes & 3) == 0) { - var size4 = attr.sizeBytes>>2; - var srcStride4 = Math.max(attr.sizeBytes, attr.stride)>>2; for (var j = 0; j < count; j++) { - for (var k = 0; k < size4; k++) { // copy in chunks of 4 bytes, our alignment makes this possible - HEAP32[((start + attr.offset + bytes*j)>>2) + k] = HEAP32[(attr.pointer>>2) + j*srcStride4 + k]; + for (var k = 0; k < attr.sizeBytes; k+=4) { // copy in chunks of 4 bytes, our alignment makes this possible + var val = {{{ makeGetValue('attr.pointer', 'j*srcStride + k', 'i32') }}}; + {{{ makeSetValue('start + attr.offset', 'bytes*j + k', 'val', 'i32') }}}; } } } else { @@ -3533,7 +3532,7 @@ var LibraryGLEmulation = { if (!GLctx.currentElementArrayBufferBinding) { assert(type == GLctx.UNSIGNED_SHORT); // We can only emulate buffers of this kind, for now } - out("DrawElements doesn't actually prepareClientAttributes properly."); + warnOnce("DrawElements doesn't actually prepareClientAttributes properly."); #endif GLImmediate.prepareClientAttributes(count, false); GLImmediate.mode = mode; diff --git a/test/test_browser.py b/test/test_browser.py index 73e62d846be0..229b4410b258 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -3050,8 +3050,6 @@ def test_sdl2_gl_read(self): # SDL, OpenGL, readPixels self.btest_exit('test_sdl2_gl_read.c', args=['-sUSE_SDL=2']) - @no_4gb('https://github.com/libsdl-org/SDL/issues/9052') - @no_2gb('https://github.com/libsdl-org/SDL/issues/9052') @requires_graphics_hardware def test_sdl2_glmatrixmode_texture(self): self.reftest('test_sdl2_glmatrixmode_texture.c', 'test_sdl2_glmatrixmode_texture.png', @@ -3105,8 +3103,6 @@ def test_sdl2_fog_linear(self): def test_sdl2_unwasteful(self): self.btest_exit('test_sdl2_unwasteful.c', args=['-sUSE_SDL=2', '-O1']) - @no_2gb('https://github.com/libsdl-org/SDL/issues/9052') - @no_4gb('https://github.com/libsdl-org/SDL/issues/9052') def test_sdl2_canvas_write(self): self.btest_exit('test_sdl2_canvas_write.c', args=['-sUSE_SDL=2']) diff --git a/tools/ports/sdl2.py b/tools/ports/sdl2.py index f2e4ec2b0758..924173ddbac7 100644 --- a/tools/ports/sdl2.py +++ b/tools/ports/sdl2.py @@ -5,8 +5,11 @@ import os -TAG = 'release-2.30.8' -HASH = '6e54c2f93c675b134ff311cb91e5f7b3ad77eb41335b172dc6d3e9774d2ea4728eba9d51667f799cfa1c52cc63169f88f0420c2330574ad3230ee0cb0642e3d4' +# For now we pin to specific commit since we want to include +# https://github.com/libsdl-org/SDL/pull/11127 +# Once the next version of SDL2 is tagged we can use that here instead. +TAG = '3deb07ea395373204462130c1e062bc1f71fe060' +HASH = '551082bffb28442ad20662c6963fb02701449d43e7da6aa68fbec922e47b060609e3cdf5f9e3bfde7458a92547e008f010af79ddadf448665e55ca8759cfbcdb' SUBDIR = 'SDL-' + TAG variants = {'sdl2-mt': {'PTHREADS': 1}} @@ -71,9 +74,6 @@ def create(final): srcs = [os.path.join(src_dir, 'src', s) for s in srcs] flags = ['-sUSE_SDL=0'] - # SDL2 currently has the wrong definition of SDL_PRIs64 for emscripten. - # TODO: Remove this when we roll SDL2 to include https://github.com/libsdl-org/SDL/pull/11127 - flags += ['-Wno-format'] includes = [ports.get_include_dir('SDL2')] if settings.PTHREADS: flags += ['-pthread'] From 814ec05f74eac9025c0442f51fa09bd8d02f8b43 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 16 Oct 2024 14:55:30 -0700 Subject: [PATCH 4/4] Fix `__errno_location` under wasm workers. NFC (#22744) Previously the wasm workers build of `__errno_location` was using the single threaded code path which doesn't use a thead local location. In addition this change avoids the use of `__EMSCRIPTEN_PTHREADS__` in `__errno_location.c` which is helpful for unifying the shared memory libc build. See #22735. --- .../libc/musl/src/errno/__errno_location.c | 21 ++++++++----------- test/code_size/hello_wasm_worker_wasm.json | 8 +++---- test/wasm_worker/thread_stack.c | 10 +++++++-- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/system/lib/libc/musl/src/errno/__errno_location.c b/system/lib/libc/musl/src/errno/__errno_location.c index dc153bce7c6d..05f55d9eaf7a 100644 --- a/system/lib/libc/musl/src/errno/__errno_location.c +++ b/system/lib/libc/musl/src/errno/__errno_location.c @@ -1,22 +1,19 @@ #include #include "pthread_impl.h" -#if __EMSCRIPTEN_PTHREADS__ -// for pthreads, use the proper location on the thread info, so each -// thread has its own errno -int *__errno_location(void) -{ - return &__pthread_self()->errno_val; -} -#else -// for single-threaded mode, avoid linking in pthreads support code -// just for this -static int __errno_storage = 0; +#if __EMSCRIPTEN__ +// For emscripten we use TLS here instead of `__pthread_self`, so that in single +// threaded builds this gets lowered away to normal global variable. +static _Thread_local int __errno_storage = 0; +#endif int *__errno_location(void) { +#if __EMSCRIPTEN__ return &__errno_storage; -} +#else + return &__pthread_self()->errno_val; #endif +} weak_alias(__errno_location, ___errno_location); diff --git a/test/code_size/hello_wasm_worker_wasm.json b/test/code_size/hello_wasm_worker_wasm.json index 8e9c264d8859..3fbf842834bd 100644 --- a/test/code_size/hello_wasm_worker_wasm.json +++ b/test/code_size/hello_wasm_worker_wasm.json @@ -5,8 +5,8 @@ "a.js.gz": 455, "a.ww.js": 115, "a.ww.js.gz": 127, - "a.wasm": 1850, - "a.wasm.gz": 1050, - "total": 3248, - "total_gz": 2016 + "a.wasm": 1894, + "a.wasm.gz": 1077, + "total": 3292, + "total_gz": 2043 } diff --git a/test/wasm_worker/thread_stack.c b/test/wasm_worker/thread_stack.c index 6d5435d6e0fd..8269555d6182 100644 --- a/test/wasm_worker/thread_stack.c +++ b/test/wasm_worker/thread_stack.c @@ -1,10 +1,12 @@ #include #include #include +#include #include #include #include +#define ALIGN(x,y) ((x)+(y)-1 & -(y)) #define THREAD_STACK_SIZE 2048 #define NUM_THREADS 2 void *thread_stack[NUM_THREADS]; @@ -18,7 +20,11 @@ void test_stack(int i) { (void*)emscripten_stack_get_end(), THREAD_STACK_SIZE); assert(emscripten_stack_get_base() == (uintptr_t)thread_stack[i] + THREAD_STACK_SIZE); - assert(emscripten_stack_get_end() == (uintptr_t)thread_stack[i]); + emscripten_outf("__builtin_wasm_tls_size: %lu", __builtin_wasm_tls_size()); + // The stack region in wasm workers also incldues TLS, so we need to take + // this into account when calulating our expected stack end. + size_t expected_stack_end = (uintptr_t)thread_stack[i] + ALIGN(__builtin_wasm_tls_size(), 16); + assert(emscripten_stack_get_end() == expected_stack_end); int ok = __sync_fetch_and_add(&threadsOk, 1); emscripten_outf("%d", ok); @@ -36,7 +42,7 @@ int main() { for (int i = 0; i < NUM_THREADS; ++i) { thread_stack[i] = memalign(16, THREAD_STACK_SIZE); emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(thread_stack[i], THREAD_STACK_SIZE); - emscripten_outf("Created thread %d with stack ptr=%p, size=%x", i, thread_stack[i], THREAD_STACK_SIZE); + emscripten_outf("Created thread %d with stack ptr=%p, end=%p, size=%x", i, thread_stack[i], thread_stack[i] + THREAD_STACK_SIZE, THREAD_STACK_SIZE); emscripten_wasm_worker_post_function_vi(worker, test_stack, i); } }