Skip to content

Commit 21dc38e

Browse files
authored
Run more low level thread primitive tests under pthreads. NFC (#26448)
These test originally ran under Wasm Workers only in the browser tests suite. This change adapts more of them so that they can also run under pthreads (and under Pthreads+wasm workers).
1 parent 285c424 commit 21dc38e

File tree

6 files changed

+180
-24
lines changed

6 files changed

+180
-24
lines changed

test/test_browser.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5171,7 +5171,7 @@ def test_wasm_worker_cancel_all_wait_asyncs_at_address(self):
51715171
# Tests emscripten_lock_init(), emscripten_lock_waitinf_acquire() and emscripten_lock_release()
51725172
@also_with_minimal_runtime
51735173
def test_wasm_worker_lock_waitinf(self):
5174-
self.btest('wasm_worker/lock_waitinf_acquire.c', expected='4000', cflags=['-sWASM_WORKERS'])
5174+
self.btest('wasm_worker/lock_waitinf_acquire.c', expected='0', cflags=['-sWASM_WORKERS'])
51755175

51765176
# Tests emscripten_lock_wait_acquire() and emscripten_lock_try_acquire() in Worker.
51775177
@also_with_minimal_runtime
@@ -5202,7 +5202,7 @@ def test_wasm_worker_lock_busyspin_wait(self):
52025202
# Tests emscripten_lock_busyspin_waitinf_acquire() in Worker and main thread.
52035203
@also_with_minimal_runtime
52045204
def test_wasm_worker_lock_busyspin_waitinf(self):
5205-
self.btest('wasm_worker/lock_busyspin_waitinf_acquire.c', expected='1', cflags=['-sWASM_WORKERS'])
5205+
self.btest('wasm_worker/lock_busyspin_waitinf_acquire.c', expected='0', cflags=['-sWASM_WORKERS'])
52065206

52075207
# Tests that proxied JS functions cannot be called from Wasm Workers
52085208
@also_with_minimal_runtime
@@ -5222,7 +5222,7 @@ def test_wasm_worker_semaphore_waitinf_acquire(self):
52225222
# Tests emscripten_semaphore_try_acquire() on the main thread
52235223
@also_with_minimal_runtime
52245224
def test_wasm_worker_semaphore_try_acquire(self):
5225-
self.btest('wasm_worker/semaphore_try_acquire.c', expected='0', cflags=['-sWASM_WORKERS'])
5225+
self.btest_exit('wasm_worker/semaphore_try_acquire.c', cflags=['-sWASM_WORKERS'])
52265226

52275227
# Tests that calling any proxied function in a Wasm Worker will abort at runtime when ASSERTIONS are enabled.
52285228
def test_wasm_worker_proxied_function(self):

test/test_core.py

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,23 @@ def metafunc(self, asyncify, *args, **kwargs):
283283
return metafunc
284284

285285

286+
def also_with_wasm_workers(func):
287+
assert callable(func)
288+
289+
@wraps(func)
290+
def metafunc(self, ww, *args, **kwargs):
291+
if ww:
292+
if self.get_setting('WASM_ESM_INTEGRATION'):
293+
self.skipTest('WASM_ESM_INTEGRATION is not compatible with WASM_WORKERS')
294+
if is_sanitizing(self.cflags):
295+
self.skipTest('sanitizers are not compatible with WASM_WORKERS')
296+
self.cflags += ['-sWASM_WORKERS']
297+
return func(self, *args, **kwargs)
298+
299+
parameterize(metafunc, {'': (False,), 'ww': (True,)})
300+
return metafunc
301+
302+
286303
def no_optimize(note=''):
287304
assert not callable(note)
288305

@@ -2749,12 +2766,33 @@ def test_pthread_run_on_main_thread(self):
27492766
def test_pthread_is_lock_free(self):
27502767
self.do_runf('pthread/is_lock_free.c', 'done\n', cflags=['-pthread'])
27512768

2769+
# These wasm_worker tests are also tested in pure wasm-worker mode in test_browser.py.
2770+
# We test them here in pthread-mode and in pthread+wasm-worker mode.
2771+
2772+
@requires_pthreads
2773+
@also_with_wasm_workers
2774+
def test_emscripten_lock_waitinf_acquire(self):
2775+
self.do_runf('wasm_worker/lock_waitinf_acquire.c', 'done\n', cflags=['-pthread', '-sPTHREAD_POOL_SIZE=4'])
2776+
27522777
@requires_pthreads
2778+
@also_with_wasm_workers
27532779
def test_emscripten_lock_wait_acquire(self):
27542780
self.do_runf('wasm_worker/lock_wait_acquire.c', 'done\n', cflags=['-pthread'])
2755-
if not is_sanitizing(self.cflags) and not self.get_setting('WASM_ESM_INTEGRATION'):
2756-
# Also test the pthreads + WASM_WORKERS combination
2757-
self.do_runf('wasm_worker/lock_wait_acquire.c', 'done\n', cflags=['-pthread', '-sWASM_WORKERS'])
2781+
2782+
@requires_pthreads
2783+
@also_with_wasm_workers
2784+
def test_emscripten_lock_busyspin_waitinf(self):
2785+
self.do_runf('wasm_worker/lock_busyspin_waitinf_acquire.c', 'done\n', cflags=['-pthread'])
2786+
2787+
@requires_pthreads
2788+
@also_with_wasm_workers
2789+
def test_emscripten_semaphore_waitinf_acquire(self):
2790+
self.do_runf('wasm_worker/semaphore_waitinf_acquire.c', 'done\n', cflags=['-pthread', '-sPTHREAD_POOL_SIZE=7'])
2791+
2792+
@requires_pthreads
2793+
@also_with_wasm_workers
2794+
def test_emscripten_semaphore_try_acquire(self):
2795+
self.do_runf('wasm_worker/semaphore_try_acquire.c', 'done\n', cflags=['-pthread'])
27582796

27592797
def test_tcgetattr(self):
27602798
self.do_runf('termios/test_tcgetattr.c', 'success')
Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1+
#include <assert.h>
12
#include <emscripten.h>
2-
#include <emscripten/wasm_worker.h>
33
#include <emscripten/threading.h>
44
#include <stdlib.h>
5-
#include <assert.h>
5+
6+
// This test can be run under pthreads *or* Wasm Workers
7+
#ifdef __EMSCRIPTEN_PTHREADS__
8+
#include <pthread.h>
9+
_Atomic bool done = false;
10+
#else
11+
#include <emscripten/wasm_worker.h>
12+
#endif
613

714
// Tests emscripten_lock_busyspin_waitinf_acquire().
815

@@ -11,29 +18,63 @@ emscripten_lock_t lock = EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER;
1118
volatile int sharedState = 0;
1219

1320
void worker_main() {
21+
emscripten_out("worker_main");
1422
emscripten_lock_busyspin_waitinf_acquire(&lock);
1523
emscripten_atomic_add_u32((void*)&sharedState, 1);
16-
#ifdef REPORT_RESULT
17-
REPORT_RESULT(sharedState);
24+
assert(sharedState == 1);
25+
#ifdef __EMSCRIPTEN_PTHREADS__
26+
emscripten_out("done");
27+
done = true;
28+
exit(0);
29+
#else
30+
REPORT_RESULT(0);
1831
#endif
1932
}
2033

34+
#ifdef __EMSCRIPTEN_PTHREADS__
35+
pthread_t t;
36+
37+
void* pthread_main(void* arg) {
38+
worker_main();
39+
return NULL;
40+
}
41+
42+
void nothing(void* userData) {
43+
if (!done) {
44+
emscripten_set_timeout(nothing, 100, 0);
45+
}
46+
}
47+
#else
2148
char stack[1024];
49+
#endif
2250

2351
void releaseLock(void *userData) {
52+
emscripten_out("releaseLock");
2453
emscripten_atomic_sub_u32((void*)&sharedState, 1);
2554
emscripten_lock_release(&lock);
2655
}
2756

2857
int main() {
58+
emscripten_out("in main");
2959
// Acquire the lock at startup.
3060
emscripten_lock_busyspin_waitinf_acquire(&lock);
3161
emscripten_atomic_add_u32((void*)&sharedState, 1);
3262

63+
#ifdef __EMSCRIPTEN_PTHREADS__
64+
// Spawn a Pthread to try to take the lock. It will succeed only after
65+
// releaseLock() gets called.
66+
pthread_create(&t, NULL, pthread_main, NULL);
67+
// Add an infinite timeout to make sure the node runtime stays alive
68+
// after main returns.
69+
// See https://github.com/emscripten-core/emscripten/issues/23092
70+
emscripten_set_timeout(nothing, 100, 0);
71+
#else
3372
// Spawn a Worker to try to take the lock. It will succeed only after releaseLock()
3473
// gets called.
3574
emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(stack, sizeof(stack));
3675
emscripten_wasm_worker_post_function_v(worker, worker_main);
76+
#endif
3777

3878
emscripten_set_timeout(releaseLock, 1000, 0);
79+
return 0;
3980
}

test/wasm_worker/lock_waitinf_acquire.c

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,26 @@
1+
#include <assert.h>
12
#include <emscripten.h>
2-
#include <emscripten/wasm_worker.h>
33
#include <emscripten/em_math.h>
44
#include <emscripten/threading.h>
55
#include <stdlib.h>
6-
#include <assert.h>
6+
7+
// This test can be run under pthreads *or* Wasm Workers
8+
#ifdef __EMSCRIPTEN_PTHREADS__
9+
#include <pthread.h>
10+
#endif
11+
12+
#ifdef __EMSCRIPTEN_WASM_WORKERS__
13+
#include <emscripten/wasm_worker.h>
14+
#else
15+
// When WASM_WORKERS is not defined we create dummy/fake version of
16+
// emscripten_wasm_worker_self_id and emscripten_wasm_worker_sleep.
17+
#define _GNU_SOURCE
18+
#include <unistd.h>
19+
int emscripten_wasm_worker_self_id() { return gettid(); }
20+
void emscripten_wasm_worker_sleep(int64_t nsecs) {
21+
emscripten_thread_sleep(nsecs / 1000000);
22+
}
23+
#endif
724

825
// Tests emscripten_lock_init(), emscripten_lock_waitinf_acquire() and emscripten_lock_release()
926

@@ -13,13 +30,19 @@ emscripten_lock_t lock = (emscripten_lock_t)12345315; // initialize with garbage
1330
volatile int sharedState0 = 0;
1431
volatile int sharedState1 = 1;
1532

16-
volatile int numWorkersAlive = 0;
33+
#define NUM_THREADS 4
34+
35+
volatile int numWorkersAlive = NUM_THREADS;
1736

1837
void test_ended() {
1938
emscripten_outf("Worker %d last thread to finish. Reporting test end with sharedState0=%d, sharedState1=%d", emscripten_wasm_worker_self_id(), sharedState0, sharedState1);
2039
assert(sharedState0 == sharedState1 + 1 || sharedState1 == sharedState0 + 1);
21-
#ifdef REPORT_RESULT
22-
REPORT_RESULT(sharedState0);
40+
assert(sharedState0 == 4000);
41+
emscripten_out("done");
42+
#if __EMSCRIPTEN_PTHREADS__
43+
exit(0);
44+
#else
45+
REPORT_RESULT(0);
2346
#endif
2447
}
2548

@@ -53,13 +76,32 @@ void worker_main() {
5376
}
5477
}
5578

79+
#ifdef __EMSCRIPTEN_PTHREADS__
80+
pthread_t threads[NUM_THREADS];
81+
82+
void* pthread_main(void* arg) {
83+
worker_main();
84+
return NULL;
85+
}
86+
#endif
87+
5688
int main() {
5789
emscripten_lock_init(&lock);
5890

59-
#define NUM_THREADS 4
60-
numWorkersAlive = NUM_THREADS;
6191
for (int i = 0; i < NUM_THREADS; ++i) {
92+
#ifdef __EMSCRIPTEN_PTHREADS__
93+
pthread_create(&threads[i], NULL, pthread_main, NULL);
94+
#else
6295
emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(1024);
6396
emscripten_wasm_worker_post_function_v(worker, worker_main);
97+
#endif
6498
}
99+
100+
#ifdef __EMSCRIPTEN_PTHREADS__
101+
for (int i = 0; i < NUM_THREADS; ++i) {
102+
pthread_join(threads[i], NULL);
103+
}
104+
#endif
105+
106+
return 0;
65107
}

test/wasm_worker/semaphore_try_acquire.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ int main() {
3030
idx = emscripten_semaphore_try_acquire(&available, 9);
3131
assert(idx == 1);
3232

33-
#ifdef REPORT_RESULT
34-
REPORT_RESULT(0);
35-
#endif
33+
emscripten_out("done");
34+
return 0;
3635
}

test/wasm_worker/semaphore_waitinf_acquire.c

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1+
#include <assert.h>
12
#include <emscripten/console.h>
2-
#include <emscripten/wasm_worker.h>
33
#include <emscripten/threading.h>
44
#include <stdlib.h>
5-
#include <assert.h>
5+
6+
#ifdef __EMSCRIPTEN_PTHREADS__
7+
#include <pthread.h>
8+
#else
9+
#include <emscripten/wasm_worker.h>
10+
#endif
611

712
// Tests emscripten_semaphore_init(), emscripten_semaphore_waitinf_acquire() and emscripten_semaphore_release()
813

14+
#define NUM_THREADS 6
15+
916
emscripten_semaphore_t threadsWaiting = (emscripten_semaphore_t)12345315; // initialize with garbage
1017
emscripten_semaphore_t threadsRunning = EMSCRIPTEN_SEMAPHORE_T_STATIC_INITIALIZER(0); // initialize with static initializer
1118
emscripten_semaphore_t threadsCompleted = EMSCRIPTEN_SEMAPHORE_T_STATIC_INITIALIZER(0);
@@ -62,20 +69,49 @@ void control_thread() {
6269
assert(threadCounter == 6);
6370

6471
emscripten_out("control_thread: test finished");
65-
#ifdef REPORT_RESULT
72+
#if defined(REPORT_RESULT) && !defined(__EMSCRIPTEN_PTHREADS__)
6673
REPORT_RESULT(0);
6774
#endif
6875
}
6976

77+
#ifdef __EMSCRIPTEN_PTHREADS__
78+
void* control_pthread(void* arg) {
79+
control_thread();
80+
return NULL;
81+
}
82+
void* worker_pthread(void* arg) {
83+
worker_main();
84+
return NULL;
85+
}
86+
#endif
87+
7088
int main() {
89+
emscripten_out("in main");
7190
emscripten_semaphore_init(&threadsWaiting, 0);
7291

92+
#ifdef __EMSCRIPTEN_PTHREADS__
93+
pthread_t p;
94+
pthread_t workers[NUM_THREADS];
95+
int rtn = pthread_create(&p, NULL, control_pthread, NULL);
96+
assert(rtn == 0);
97+
98+
for (int i = 0; i < NUM_THREADS; ++i) {
99+
rtn = pthread_create(&workers[i], NULL, worker_pthread, NULL);
100+
assert(rtn == 0);
101+
}
102+
103+
pthread_join(p, NULL);
104+
for (int i = 0; i < NUM_THREADS; ++i) {
105+
pthread_join(workers[i], NULL);
106+
}
107+
emscripten_out("done");
108+
#else
73109
emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(1024);
74110
emscripten_wasm_worker_post_function_v(worker, control_thread);
75111

76-
#define NUM_THREADS 6
77112
for (int i = 0; i < NUM_THREADS; ++i) {
78113
emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(1024);
79114
emscripten_wasm_worker_post_function_v(worker, worker_main);
80115
}
116+
#endif
81117
}

0 commit comments

Comments
 (0)