Skip to content

Commit 071a233

Browse files
committed
Fix multithreading support for Deno and Bun
Fixes denoland/deno#17171 Also adds several pthread tests with Bun
1 parent f216821 commit 071a233

File tree

5 files changed

+41
-20
lines changed

5 files changed

+41
-20
lines changed

.circleci/config.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,8 @@ jobs:
872872
- upload-test-results
873873
test-bun:
874874
executor: linux-python
875+
environment:
876+
OVERRIDE_NODE_JS_TEST_VERSION: "v24.0.0"
875877
steps:
876878
- checkout
877879
- pip-install
@@ -880,10 +882,14 @@ jobs:
880882
name: install bun
881883
command: |
882884
curl -fsSL https://bun.com/install | bash
883-
echo "BUN_ENGINE = os.path.expanduser('~/.bun/bin/bun')" >> ~/emsdk/.emscripten
884-
echo "JS_ENGINES = [BUN_ENGINE]" >> ~/emsdk/.emscripten
885+
echo "NODE_JS_TEST = os.path.expanduser('~/.bun/bin/bun')" >> ~/emsdk/.emscripten
886+
echo "JS_ENGINES = [NODE_JS_TEST]" >> ~/emsdk/.emscripten
885887
- run-tests:
886-
test_targets: "core0.test_hello_world"
888+
test_targets: "
889+
core0.test_hello_world
890+
core0.test_hello_argc_pthreads
891+
core2.test_pthread_create
892+
"
887893
test-jsc:
888894
executor: linux-python
889895
steps:

src/pthread_esm_startup.mjs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@ console.log("Running pthread_esm_startup");
1616
#if ENVIRONMENT_MAY_BE_NODE
1717
if ({{{ nodeDetectionCode() }}}) {
1818
// Create as web-worker-like an environment as we can.
19+
globalThis.self = globalThis;
1920
var worker_threads = await import('worker_threads');
20-
global.Worker = worker_threads.Worker;
21+
globalThis.Worker = worker_threads.Worker;
2122
var parentPort = worker_threads['parentPort'];
22-
parentPort.on('message', (msg) => global.onmessage?.({ data: msg }));
23-
Object.assign(globalThis, {
24-
self: global,
25-
postMessage: (msg) => parentPort['postMessage'](msg),
26-
});
23+
// Deno and Bun already have `postMessage` defined on the global scope and
24+
// deliver messages to `globalThis.onmessage`, so we must not duplicate that
25+
// behavior here if `postMessage` is already present.
26+
if (!globalThis.postMessage) {
27+
parentPort.on('message', (msg) => globalThis.onmessage?.({ data: msg }));
28+
globalThis.postMessage = (msg) => parentPort['postMessage'](msg);
29+
}
2730
}
2831
#endif
2932

src/runtime_common.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,15 @@ var readyPromiseResolve, readyPromiseReject;
3838
#if (PTHREADS || WASM_WORKERS) && (ENVIRONMENT_MAY_BE_NODE && !WASM_ESM_INTEGRATION)
3939
if (ENVIRONMENT_IS_NODE && {{{ ENVIRONMENT_IS_WORKER_THREAD() }}}) {
4040
// Create as web-worker-like an environment as we can.
41+
globalThis.self = globalThis;
4142
var parentPort = worker_threads['parentPort'];
42-
parentPort.on('message', (msg) => global.onmessage?.({ data: msg }));
43-
Object.assign(globalThis, {
44-
self: global,
45-
postMessage: (msg) => parentPort['postMessage'](msg),
46-
});
43+
// Deno and Bun already have `postMessage` defined on the global scope and
44+
// deliver messages to `globalThis.onmessage`, so we must not duplicate that
45+
// behavior here if `postMessage` is already present.
46+
if (!globalThis.postMessage) {
47+
parentPort.on('message', (msg) => globalThis.onmessage?.({ data: msg }));
48+
globalThis.postMessage = (msg) => parentPort['postMessage'](msg);
49+
}
4750
// Node.js Workers do not pass postMessage()s and uncaught exception events to the parent
4851
// thread necessarily in the same order where they were generated in sequential program order.
4952
// See https://github.com/nodejs/node/issues/59617

test/common.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,15 @@ def require_node(self):
393393
self.require_engine(nodejs)
394394
return nodejs
395395

396+
def get_node_test_version(nodejs):
397+
override = os.environ.get('OVERRIDE_NODE_JS_TEST_VERSION')
398+
if override:
399+
override = override.removeprefix('v')
400+
override = override.split('-')[0].split('.')
401+
override = tuple(int(v) for v in override)
402+
return override
403+
return shared.get_node_version(nodejs)
404+
396405
def node_is_canary(self, nodejs):
397406
return nodejs and nodejs[0] and ('canary' in nodejs[0] or 'nightly' in nodejs[0])
398407

@@ -435,7 +444,7 @@ def try_require_node_version(self, major, minor = 0, revision = 0):
435444
nodejs = self.get_nodejs()
436445
if not nodejs:
437446
self.skipTest('Test requires nodejs to run')
438-
version = shared.get_node_version(nodejs)
447+
version = self.get_node_test_version(nodejs)
439448
if version < (major, minor, revision):
440449
return False
441450

@@ -622,7 +631,7 @@ def setUp(self):
622631

623632
nodejs = self.get_nodejs()
624633
if nodejs:
625-
node_version = shared.get_node_version(nodejs)
634+
node_version = self.get_node_test_version(nodejs)
626635
if node_version < (13, 0, 0):
627636
self.node_args.append('--unhandled-rejections=strict')
628637
elif node_version < (15, 0, 0):

test/test_other.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3682,7 +3682,7 @@ def test_embind_tsgen_jspi(self):
36823682
'legacy': [1],
36833683
})
36843684
def test_embind_tsgen_exceptions(self, legacy):
3685-
if not legacy and shared.get_node_version(config.NODE_JS)[0] < 22:
3685+
if not legacy and self.get_node_test_version(config.NODE_JS)[0] < 22:
36863686
self.skipTest('Node version needs to be 22 or greater to run tsgen with Wasm EH')
36873687
self.set_setting('WASM_LEGACY_EXCEPTIONS', legacy)
36883688

@@ -12368,7 +12368,7 @@ def test_gen_struct_info(self):
1236812368
self.assertFileContents(path_from_root('src/struct_info_generated.json'), read_file('out.json'))
1236912369

1237012370
# Same again for wasm64
12371-
node_version = shared.get_node_version(self.get_nodejs())
12371+
node_version = self.get_node_test_version(self.get_nodejs())
1237212372
if node_version and node_version >= (14, 0, 0):
1237312373
self.run_process([PYTHON, path_from_root('tools/gen_struct_info.py'), '--wasm64', '-o', 'out.json'])
1237412374
self.assertFileContents(path_from_root('src/struct_info_generated_wasm64.json'), read_file('out.json'))
@@ -12881,7 +12881,7 @@ def test_node_unhandled_rejection(self):
1288112881
self.build('main.c', cflags=['--pre-js=pre.js', '-sNODEJS_CATCH_REJECTION=0'])
1288212882
self.assertNotContained('unhandledRejection', read_file('main.js'))
1288312883

12884-
if shared.get_node_version(self.get_nodejs())[0] >= 15:
12884+
if self.get_node_test_version(self.get_nodejs())[0] >= 15:
1288512885
self.skipTest('old behaviour of node JS cannot be tested on node v15 or above')
1288612886

1288712887
output = self.run_js('main.js')
@@ -13960,7 +13960,7 @@ def test_parseTools_legacy(self):
1396013960

1396113961
@requires_node
1396213962
def test_min_node_version(self):
13963-
node_version = shared.get_node_version(self.get_nodejs())
13963+
node_version = self.get_node_test_version(self.get_nodejs())
1396413964
node_version = '.'.join(str(x) for x in node_version)
1396513965
self.set_setting('MIN_NODE_VERSION', 300000)
1396613966
expected = 'This emscripten-generated code requires node v30.0.0 (detected v%s' % node_version

0 commit comments

Comments
 (0)