Skip to content

Commit da2bcaa

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 fce11ef commit da2bcaa

File tree

15 files changed

+112
-124
lines changed

15 files changed

+112
-124
lines changed

ChangeLog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ See docs/process.md for more on how version tagging works.
3030
This is an extension of #26336 which removed many of them. These APIs were
3131
not previously functional under Wasm Workers, but if there is strong use case
3232
it may be possible to enable them in future. (#26487)
33+
- Pthread mutex/cond/rwlock primitives now work from with Wasm Workers (and
34+
between Wasm Workers and pthreads). (#26510)
3335

3436
5.0.3 - 03/14/26
3537
----------------

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)