Skip to content

Commit 5b71588

Browse files
committed
Enable pthread mutex/cond/rw_lock to be used in Wasm Workers
By using the `CURRENT_THREAD_ID` abstraction that already exists in musl these primitives "just work" for Wasm Workers now. This includes a partial revert of #26345.
1 parent 4f40164 commit 5b71588

File tree

15 files changed

+64
-78
lines changed

15 files changed

+64
-78
lines changed

ChangeLog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ See docs/process.md for more on how version tagging works.
2626
- The deprecated `EMSCRIPTEN` macro is now defined in `emscripten.h` rather than
2727
on the command line (`__EMSCRIPTEN__`, which is built into LLVM, should be
2828
used instead). (#26417)
29+
- Pthread mutex/cond/rwlock primitives now work from with Wasm Workers (and
30+
between Wasm Workers and pthreads). (#26510)
2931

3032
5.0.3 - 03/14/26
3133
----------------

site/source/docs/api_reference/wasm_workers.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,15 @@ Pthreads and Wasm Workers share several similarities:
8989
* Both can use emscripten_futex_wait/wake API,
9090
* Both can use GCC __sync_* Atomics API,
9191
* Both can use C11 and C++11 Atomics APIs,
92+
* Both can use pthread_mutex/pthread_cond/pthread_rwlock/pthread_once APIs.
9293
* Both types of threads have a local stack.
9394
* Both types of threads have thread-local storage (TLS) support via ``thread_local`` (C++11),
9495
``_Thread_local`` (C11) and ``__thread`` (GNU11) keywords.
9596
* Both types of threads support TLS via explicitly linked in Wasm globals (see
9697
``test/wasm_worker/wasm_worker_tls_wasm_assembly.c/.S`` for example code)
9798
* Both types of threads have a concept of a thread ID (``pthread_self()`` for pthreads,
98-
``emscripten_wasm_worker_self_id()`` for Wasm Workers)
99+
``emscripten_wasm_worker_self_id()`` for Wasm Workers). `gettid()` works in
100+
both contexts so is more portable.
99101
* Both types of threads can perform an event-based and an infinite loop programming model.
100102
* Both can use ``EM_ASM`` and ``EM_JS`` API to execute JS code on the calling thread.
101103
* Both can call out to JS library functions (linked in with ``--js-library`` directive) to

src/lib/libatomic.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,4 +161,23 @@ addToLibrary({
161161
navigator['hardwareConcurrency'],
162162

163163
emscripten_atomics_is_lock_free: (width) => Atomics.isLockFree(width),
164+
165+
#if (ASSERTIONS || !ALLOW_BLOCKING_ON_MAIN_THREAD) && !MINIMAL_RUNTIME
166+
emscripten_check_blocking_allowed__deps: ['$warnOnce'],
167+
#endif
168+
emscripten_check_blocking_allowed: () => {
169+
#if (ASSERTIONS || !ALLOW_BLOCKING_ON_MAIN_THREAD) && !MINIMAL_RUNTIME
170+
#if ENVIRONMENT_MAY_BE_NODE
171+
if (ENVIRONMENT_IS_NODE) return;
172+
#endif
173+
174+
if (ENVIRONMENT_IS_WORKER) return; // Blocking in a worker/pthread is fine.
175+
176+
warnOnce('Blocking on the main thread is very dangerous, see https://emscripten.org/docs/porting/pthreads.html#blocking-on-the-main-browser-thread');
177+
#if !ALLOW_BLOCKING_ON_MAIN_THREAD
178+
abort('Blocking on the main thread is not allowed by default. See https://emscripten.org/docs/porting/pthreads.html#blocking-on-the-main-browser-thread');
179+
#endif
180+
181+
#endif
182+
},
164183
});

src/lib/libpthread.js

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -904,25 +904,6 @@ var LibraryPThread = {
904904
return spawnThread(threadParams);
905905
},
906906
907-
#if (ASSERTIONS || !ALLOW_BLOCKING_ON_MAIN_THREAD) && !MINIMAL_RUNTIME
908-
emscripten_check_blocking_allowed__deps: ['$warnOnce'],
909-
#endif
910-
emscripten_check_blocking_allowed: () => {
911-
#if (ASSERTIONS || !ALLOW_BLOCKING_ON_MAIN_THREAD) && !MINIMAL_RUNTIME
912-
#if ENVIRONMENT_MAY_BE_NODE
913-
if (ENVIRONMENT_IS_NODE) return;
914-
#endif
915-
916-
if (ENVIRONMENT_IS_WORKER) return; // Blocking in a worker/pthread is fine.
917-
918-
warnOnce('Blocking on the main thread is very dangerous, see https://emscripten.org/docs/porting/pthreads.html#blocking-on-the-main-browser-thread');
919-
#if !ALLOW_BLOCKING_ON_MAIN_THREAD
920-
abort('Blocking on the main thread is not allowed by default. See https://emscripten.org/docs/porting/pthreads.html#blocking-on-the-main-browser-thread');
921-
#endif
922-
923-
#endif
924-
},
925-
926907
// This function is called by a pthread to signal that exit() was called and
927908
// that the entire process should exit.
928909
// This function is always called from a pthread, but is executed on the

system/lib/libc/musl/src/temp/__randname.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ char *__randname(char *template)
1111
unsigned long r;
1212

1313
__clock_gettime(CLOCK_REALTIME, &ts);
14-
r = ts.tv_sec + ts.tv_nsec + __pthread_self()->tid * 65537UL;
14+
r = ts.tv_sec + ts.tv_nsec + CURRENT_THREAD_ID * 65537UL;
1515

1616
/* XXX EMSCRIPTEN: avoid repeating the same result when __clock_gettime does not change between calls. */
1717
static unsigned int counter = 0;

system/lib/libc/musl/src/thread/pthread_cond_timedwait.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ int __pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restri
8282
}
8383
#endif
8484

85-
if ((m->_m_type&15) && (m->_m_lock&INT_MAX) != __pthread_self()->tid)
85+
if ((m->_m_type&15) && (m->_m_lock&INT_MAX) != CURRENT_THREAD_ID)
8686
return EPERM;
8787

8888
if (ts && ts->tv_nsec >= 1000000000UL)

system/lib/libc/musl/src/thread/pthread_mutex_consistent.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ int pthread_mutex_consistent(pthread_mutex_t *m)
77
int own = old & 0x3fffffff;
88
if (!(m->_m_type & 4) || !own || !(old & 0x40000000))
99
return EINVAL;
10-
if (own != __pthread_self()->tid)
10+
if (own != CURRENT_THREAD_ID)
1111
return EPERM;
1212
a_and(&m->_m_lock, ~0x40000000);
1313
return 0;

system/lib/libc/musl/src/thread/pthread_mutex_timedlock.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,12 @@ int __pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec
8787
if (!own && (!r || (type&4)))
8888
continue;
8989
if ((type&3) == PTHREAD_MUTEX_ERRORCHECK
90-
&& own == __pthread_self()->tid)
90+
&& own == CURRENT_THREAD_ID)
9191
return EDEADLK;
9292
#if defined(__EMSCRIPTEN__) && !defined(NDEBUG)
9393
// Extra check for deadlock in debug builds, but only if we would block
9494
// forever (at == NULL).
95-
assert(at || own != __pthread_self()->tid && "pthread mutex deadlock detected");
95+
assert(at || own != CURRENT_THREAD_ID && "pthread mutex deadlock detected");
9696
#endif
9797

9898
a_inc(&m->_m_waiters);

system/lib/libc/musl/src/thread/pthread_rwlock_timedwrlock.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ int __pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rw, const struct tim
55
#ifdef __EMSCRIPTEN__
66
/// XXX Emscripten: The spec allows detecting when multiple write locks would deadlock, which we do here to avoid hangs.
77
/// If attempting to lock the write lock that we already own, error out.
8-
if (rw->_rw_wr_owner == __pthread_self()->tid) return EDEADLK;
8+
if (rw->_rw_wr_owner == CURRENT_THREAD_ID) return EDEADLK;
99
#endif
1010
int r, t;
1111

@@ -27,7 +27,7 @@ int __pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rw, const struct tim
2727
#ifdef __EMSCRIPTEN__
2828
/// XXX Emscripten: The spec allows detecting when multiple write locks would deadlock, which we do here to avoid hangs.
2929
/// Mark this thread as the owner of this write lock.
30-
rw->_rw_wr_owner = __pthread_self()->tid;
30+
rw->_rw_wr_owner = CURRENT_THREAD_ID;
3131
#endif
3232
return r;
3333
}

system/lib/libc/musl/src/thread/pthread_rwlock_trywrlock.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ int __pthread_rwlock_trywrlock(pthread_rwlock_t *rw)
66
#ifdef __EMSCRIPTEN__
77
/// XXX Emscripten: The spec allows detecting when multiple write locks would deadlock, which we do here to avoid hangs.
88
/// Mark this thread to own the write lock, to ignore multiple attempts to lock.
9-
rw->_rw_wr_owner = __pthread_self()->tid;
9+
rw->_rw_wr_owner = CURRENT_THREAD_ID;
1010
#endif
1111
return 0;
1212
}

0 commit comments

Comments
 (0)