Skip to content

Commit 3f6a380

Browse files
authored
Enable gettid() under WASM_WORKERS (#26472)
This change doesn't look very useful but as followup to this (and combined with #26468) this should allow us to enable more internal musl locking code that currently depends on `pthread_self()->tid`.
1 parent bc82b78 commit 3f6a380

File tree

5 files changed

+55
-14
lines changed

5 files changed

+55
-14
lines changed

src/lib/libwasm_worker.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,16 @@
6565

6666
addToLibrary({
6767
$_wasmWorkers: {},
68+
#if PTHREADS
69+
// When the build contains both pthreads and Wasm Workers, offset the
70+
// Wasm Worker ID space to avoid collisions with pthread TIDs (which start
71+
// at 42). We use `1 << 30` since it's ~1/2 way through `pid_t` space,
72+
// essentially giving pthreads the first 1/2 of the range and wasm workers the
73+
// second half.
74+
$_wasmWorkersID: {{{ 1 << 30 }}},
75+
#else
6876
$_wasmWorkersID: 1,
77+
#endif
6978

7079
// Starting up a Wasm Worker is an asynchronous operation, hence if the parent
7180
// thread performs any postMessage()-based wasm function calls to the

system/lib/libc/musl/src/linux/gettid.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,30 @@
22
#include <unistd.h>
33
#include "pthread_impl.h"
44

5+
#ifdef __EMSCRIPTEN_WASM_WORKERS__
6+
#include <emscripten/wasm_worker.h>
7+
#elif defined(__EMSCRIPTEN_PTHREADS__)
8+
weak int emscripten_wasm_worker_self_id();
9+
#endif
10+
11+
#if defined(__EMSCRIPTEN_WASM_WORKERS__) && defined(__EMSCRIPTEN_PTHREADS__)
12+
#error "this file should be compiled with either wasm workers or pthreads but not both"
13+
#endif
14+
515
pid_t gettid(void)
616
{
17+
#ifdef __EMSCRIPTEN_WASM_WORKERS__
18+
// Offset the worker ID by 1 so we never return 0 from this function.
19+
return emscripten_wasm_worker_self_id() + 1;
20+
#else
21+
#if defined(__EMSCRIPTEN_PTHREADS__)
22+
// The pthread-variant of libc can also be used alongside wasm workers.
23+
// We detect that via a weak reference to the self_id function.
24+
if (emscripten_wasm_worker_self_id) {
25+
pid_t rtn = emscripten_wasm_worker_self_id();
26+
if (rtn) return rtn;
27+
}
28+
#endif
729
return __pthread_self()->tid;
30+
#endif
831
}

test/test_browser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5076,7 +5076,7 @@ def test_wasm_worker_malloc(self):
50765076
# Tests Wasm Worker+pthreads simultaneously
50775077
@also_with_minimal_runtime
50785078
def test_wasm_worker_and_pthreads(self):
5079-
self.btest('wasm_worker/wasm_worker_and_pthread.c', expected='0', cflags=['-sWASM_WORKERS', '-pthread'])
5079+
self.btest('wasm_worker/wasm_worker_and_pthread.c', expected='0', cflags=['-sWASM_WORKERS', '-pthread', '-sPTHREAD_POOL_SIZE=1'])
50805080

50815081
# Tests emscripten_wasm_worker_self_id() function
50825082
@also_with_minimal_runtime

test/wasm_worker/lock_waitinf_acquire.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
#include <emscripten/threading.h>
55
#include <stdlib.h>
66

7+
#define _GNU_SOURCE
8+
#include <unistd.h> // for gettid
9+
710
// This test can be run under pthreads *or* Wasm Workers
811
#ifdef __EMSCRIPTEN_PTHREADS__
912
#include <pthread.h>
@@ -13,10 +16,7 @@
1316
#include <emscripten/wasm_worker.h>
1417
#else
1518
// 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(); }
19+
// emscripten_wasm_worker_sleep.
2020
void emscripten_wasm_worker_sleep(int64_t nsecs) {
2121
emscripten_thread_sleep(nsecs / 1000000);
2222
}
@@ -35,7 +35,7 @@ volatile int sharedState1 = 1;
3535
volatile int numWorkersAlive = NUM_THREADS;
3636

3737
void test_ended() {
38-
emscripten_outf("Worker %d last thread to finish. Reporting test end with sharedState0=%d, sharedState1=%d", emscripten_wasm_worker_self_id(), sharedState0, sharedState1);
38+
emscripten_outf("Worker %d last thread to finish. Reporting test end with sharedState0=%d, sharedState1=%d", gettid(), sharedState0, sharedState1);
3939
assert(sharedState0 == sharedState1 + 1 || sharedState1 == sharedState0 + 1);
4040
assert(sharedState0 == 4000);
4141
emscripten_out("done");
@@ -47,7 +47,7 @@ void test_ended() {
4747
}
4848

4949
void worker_main() {
50-
emscripten_outf("Worker %d running...", emscripten_wasm_worker_self_id());
50+
emscripten_outf("Worker %d running...", gettid());
5151
// Create contention on the lock from each thread, and stress the shared state
5252
// in a racy way that would show a breakage if the lock is not watertight.
5353
for (int i = 0; i < 1000; ++i) {
@@ -67,7 +67,7 @@ void worker_main() {
6767
emscripten_lock_release(&lock);
6868
}
6969

70-
emscripten_outf("Worker %d finished.", emscripten_wasm_worker_self_id());
70+
emscripten_outf("Worker %d finished.", gettid());
7171

7272
// Are we the last thread to finish? If so, test has ended.
7373
uint32_t v = emscripten_atomic_sub_u32((void*)&numWorkersAlive, 1);

test/wasm_worker/wasm_worker_and_pthread.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@
44
#include <emscripten/threading.h>
55
#include <emscripten/console.h>
66
#include <assert.h>
7+
#define _GNU_SOURCE // for gettid
8+
#include <unistd.h>
79

8-
volatile int pthread_ran = 0;
10+
_Atomic pid_t main_tid = 0;
11+
_Atomic pid_t pthread_tid = 0;
12+
_Atomic pid_t worker_tid = 0;
913

1014
EM_JS(int, am_i_pthread, (), {
1115
return ENVIRONMENT_IS_PTHREAD;
@@ -16,32 +20,37 @@ EM_JS(int, am_i_wasm_worker, (), {
1620
});
1721

1822
void *thread_main(void *arg) {
19-
emscripten_out("hello from pthread!");
23+
pthread_tid = gettid();
24+
emscripten_outf("hello from pthread! (tid=%d)", pthread_tid);
25+
assert(pthread_tid && pthread_tid > main_tid);
2026
assert(am_i_pthread());
2127
assert(!am_i_wasm_worker());
2228
assert(!emscripten_current_thread_is_wasm_worker());
2329
assert(emscripten_wasm_worker_self_id() == 0);
24-
pthread_ran = 1;
2530
return 0;
2631
}
2732

2833
void worker_main() {
29-
emscripten_out("hello from wasm worker!");
34+
worker_tid = gettid();
35+
emscripten_outf("hello from wasm worker! (tid=%d)", worker_tid);
36+
assert(worker_tid && worker_tid > pthread_tid);
3037
assert(!am_i_pthread());
3138
assert(am_i_wasm_worker());
3239
assert(emscripten_current_thread_is_wasm_worker());
3340
assert(emscripten_wasm_worker_self_id() != 0);
3441

35-
while(!emscripten_atomic_cas_u32((void*)&pthread_ran, 0, 1))
36-
emscripten_wasm_worker_sleep(10);
3742
#ifdef REPORT_RESULT
3843
REPORT_RESULT(0);
3944
#endif
4045
}
4146

4247
int main() {
48+
main_tid = gettid();
49+
emscripten_outf("in main (tid=%d)", main_tid);
50+
assert(main_tid > 0);
4351
pthread_t thread;
4452
pthread_create(&thread, NULL, thread_main, NULL);
53+
pthread_join(thread, NULL);
4554

4655
emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(/*stack size: */1024);
4756
emscripten_wasm_worker_post_function_v(worker, worker_main);

0 commit comments

Comments
 (0)