Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ See docs/process.md for more on how version tagging works.

5.0.3 (in development)
----------------------
- When building with `-sWASM_WORKERS` emscripten will no longer include pthread
API stub functions. These stub functions where never designed to work under

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
API stub functions. These stub functions where never designed to work under
API stub functions. These stub functions were never designed to work under

Wasm Workers, so its safer to error at link time if pthread APIs are used
in Wasm Worker-based programs. (#26336)

5.0.2 - 02/25/26
----------------
Expand Down
17 changes: 17 additions & 0 deletions system/lib/libc/emscripten_yield_stub.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright 2026 The Emscripten Authors. All rights reserved.
* Emscripten is available under two separate licenses, the MIT license and the
* University of Illinois/NCSA Open Source License. Both these licenses can be
* found in the LICENSE file.
*/

#include <features.h>

static void dummy(double now) {
}

weak_alias(dummy, _emscripten_check_timers);

void _emscripten_yield(double now) {
_emscripten_check_timers(now);
}
16 changes: 4 additions & 12 deletions system/lib/pthread/library_pthread_stub.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@
#include <emscripten/threading.h>
#include <emscripten/emscripten.h>

#ifdef __EMSCRIPTEN_WASM_WORKERS__
#error "This file contains stubs that should not be included in wasm workers builds."
#endif

bool emscripten_has_threading_support() { return false; }

int emscripten_num_logical_cores() { return 1; }

#ifndef __EMSCRIPTEN_WASM_WORKERS__
// These low level primites are defined in both pthreads and wasm workers
// builds.

Expand Down Expand Up @@ -55,7 +58,6 @@ void __unlock(void* ptr) {}
void __acquire_ptc() {}

void __release_ptc() {}
#endif

void emscripten_main_thread_process_queued_calls() {
// nop
Expand All @@ -65,16 +67,6 @@ void emscripten_current_thread_process_queued_calls() {
// nop
}

static void dummy(double now)
{
}

weak_alias(dummy, _emscripten_check_timers);

void _emscripten_yield(double now) {
_emscripten_check_timers(now);
}

int pthread_mutex_init(
pthread_mutex_t* __restrict mutex, const pthread_mutexattr_t* __restrict attr) {
return 0;
Expand Down
10 changes: 10 additions & 0 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -13519,6 +13519,16 @@ def test_shared_memory_preprocessor_flags(self):
def test_wasm_worker_preprocessor_flags(self):
self.run_process([EMCC, '-c', test_file('wasm_worker/wasm_worker_preprocessor_flags.c'), '-sWASM_WORKERS'])

@also_with_minimal_runtime
def test_wasm_worker_pthread_api_usage(self):
self.assert_fail([EMCC, test_file('wasm_worker/wasm_worker_pthread_api_usage.c'), '-sWASM_WORKERS'], 'undefined symbol: pthread_mutex_lock')

@also_with_minimal_runtime
def test_wasm_worker_cxx_init(self):
# For now, C++ init guards do not work with Wasm Workers.
# See https://github.com/emscripten-core/emscripten/issues/26277
self.assert_fail([EMCC, test_file('wasm_worker/wasm_worker_cxx_init.cpp'), '-sWASM_WORKERS'], 'undefined symbol: pthread_cond_wait')

@parameterized({
# we will warn here since -O2 runs the optimizer and -g enables DWARF
'O2_g': (True, ['-O2', '-g']),
Expand Down
28 changes: 28 additions & 0 deletions test/wasm_worker/wasm_worker_cxx_init.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <stdio.h>

struct Foo {
Foo() {
printf("create Foo\n");
}

~Foo() {
printf("destroy Foo\n");
}

void baz() {
printf("method called\n");
}
};


void bar() {
static Foo foo;
foo.baz();
}

int main() {
printf("main\n");
bar();
printf("done\n");
return 0;
}
7 changes: 7 additions & 0 deletions test/wasm_worker/wasm_worker_pthread_api_usage.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <pthread.h>

int main() {
// This program should fail to link with WASM_WORKERS.
pthread_mutex_t my_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&my_mutex);
}
21 changes: 15 additions & 6 deletions tools/system_libs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1256,13 +1256,10 @@ def get_files(self):
'thrd_sleep.c',
'thrd_yield.c',
])

libc_files += files_in_path(
path='system/lib/pthread',
filenames=[
'library_pthread_stub.c',
'pthread_self_stub.c',
'proxying_stub.c',
])
path='system/lib/libc',
filenames=['emscripten_yield_stub.c'])

if self.is_ww:
libc_files += files_in_path(
Expand All @@ -1272,6 +1269,18 @@ def get_files(self):
'__wait.c',
'lock_ptc.c',
])
else:
# Include stub version of thread functions when building
# in single theaded mode.
# Note: We do *not* include these stubs in the Wasm Workers build since it would
# never be safe to call these from a Wasm Worker.
libc_files += files_in_path(
path='system/lib/pthread',
filenames=[
'library_pthread_stub.c',
'pthread_self_stub.c',
'proxying_stub.c',
])

if self.is_mt or self.is_ww:
# Low level thread primitives available in both pthreads and wasm workers builds.
Expand Down