Skip to content

Commit a23f797

Browse files
committed
Fix the WASM Worker cannot start in node.js environment
`emscripten_malloc_wasm_worker` and `emscripten_create_wasm_worker` functions adapted to the nodejs environment and modified the core related tests.
1 parent 19c52e0 commit a23f797

File tree

9 files changed

+119
-34
lines changed

9 files changed

+119
-34
lines changed

emscripten.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,7 @@ def create_pointer_conversion_wrappers(metadata):
912912
'__main_argc_argv': '__PP',
913913
'emscripten_stack_set_limits': '_pp',
914914
'__set_stack_limits': '_pp',
915+
'__set_thread_state': '_p___',
915916
'__cxa_can_catch': '_ppp',
916917
'__cxa_increment_exception_refcount': '_p',
917918
'__cxa_decrement_exception_refcount': '_p',

src/library_wasi.js

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,8 @@ var WasiLibrary = {
229229
}
230230
return ret;
231231
},
232-
#else
232+
#endif
233+
#if !SYSCALLS_REQUIRE_FILESYSTEM || WASM_WORKERS
233234
// MEMFS filesystem disabled lite handling of stdout and stderr:
234235
$printCharBuffers: [null, [], []], // 1 => stdout, 2 => stderr
235236
$printCharBuffers__internal: true,
@@ -247,11 +248,7 @@ var WasiLibrary = {
247248
buffer.push(curr);
248249
}
249250
},
250-
#endif // SYSCALLS_REQUIRE_FILESYSTEM
251-
252-
#if SYSCALLS_REQUIRE_FILESYSTEM
253-
fd_write__deps: ['$doWritev'],
254-
#elif (!MINIMAL_RUNTIME || EXIT_RUNTIME)
251+
#if !MINIMAL_RUNTIME || EXIT_RUNTIME
255252
$flush_NO_FILESYSTEM__deps: ['$printChar', '$printCharBuffers'],
256253
$flush_NO_FILESYSTEM: () => {
257254
// flush anything remaining in the buffers during shutdown
@@ -261,17 +258,13 @@ var WasiLibrary = {
261258
if (printCharBuffers[1].length) printChar(1, {{{ charCode("\n") }}});
262259
if (printCharBuffers[2].length) printChar(2, {{{ charCode("\n") }}});
263260
},
264-
fd_write__deps: ['$flush_NO_FILESYSTEM', '$printChar'],
265-
fd_write__postset: () => addAtExit('flush_NO_FILESYSTEM()'),
261+
$fd_write_nofs__postset: () => addAtExit('flush_NO_FILESYSTEM()'),
262+
$fd_write_nofs__deps: ['$printChar', '$flush_NO_FILESYSTEM'],
266263
#else
267-
fd_write__deps: ['$printChar'],
264+
$fd_write_nofs__deps: ['$printChar'],
268265
#endif
269-
fd_write: (fd, iov, iovcnt, pnum) => {
270-
#if SYSCALLS_REQUIRE_FILESYSTEM
271-
var stream = SYSCALLS.getStreamFromFD(fd);
272-
var num = doWritev(stream, iov, iovcnt);
273-
#else
274-
// hack to support printf in SYSCALLS_REQUIRE_FILESYSTEM=0
266+
$fd_write_nofs__sig: 'iippp',
267+
$fd_write_nofs: (fd, iov, iovcnt, pnum) => {
275268
var num = 0;
276269
for (var i = 0; i < iovcnt; i++) {
277270
var ptr = {{{ makeGetValue('iov', C_STRUCTS.iovec.iov_base, '*') }}};
@@ -282,10 +275,36 @@ var WasiLibrary = {
282275
}
283276
num += len;
284277
}
285-
#endif // SYSCALLS_REQUIRE_FILESYSTEM
286278
{{{ makeSetValue('pnum', 0, 'num', SIZE_TYPE) }}};
287279
return 0;
288280
},
281+
#endif
282+
283+
#if SYSCALLS_REQUIRE_FILESYSTEM
284+
fd_write__deps: [
285+
'$doWritev',
286+
#if WASM_WORKERS
287+
'$fd_write_nofs',
288+
#endif
289+
],
290+
fd_write: (fd, iov, iovcnt, pnum) => {
291+
#if WASM_WORKERS
292+
if (ENVIRONMENT_IS_WASM_WORKER) {
293+
return fd_write_nofs(fd, iov, iovcnt, pnum);
294+
}
295+
#endif // WASM_WORKERS
296+
var stream = SYSCALLS.getStreamFromFD(fd);
297+
var num = doWritev(stream, iov, iovcnt);
298+
{{{ makeSetValue('pnum', 0, 'num', SIZE_TYPE) }}};
299+
return 0;
300+
},
301+
#else
302+
fd_write__deps: ['$fd_write_nofs'],
303+
fd_write: (fd, iov, iovcnt, pnum) => {
304+
// May be wrapped by wrapSyscallFunction
305+
return fd_write_nofs(fd, iov, iovcnt, pnum);
306+
},
307+
#endif
289308

290309
#if SYSCALLS_REQUIRE_FILESYSTEM
291310
fd_pwrite__deps: ['$doWritev'],

src/library_wasm_worker.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,12 @@ addToLibrary({
4747
$_wasmWorkerRunPostMessage: (e) => {
4848
// '_wsc' is short for 'wasm call', trying to use an identifier name that
4949
// will never conflict with user code
50-
let data = e.data, wasmCall = data['_wsc'];
50+
#if ENVIRONMENT_MAY_BE_NODE
51+
let data = ENVIRONMENT_IS_NODE ? e : e.data;
52+
#else
53+
let data = e.data;
54+
#endif
55+
let wasmCall = data['_wsc'];
5156
wasmCall && getWasmTableEntry(wasmCall)(...data['x']);
5257
},
5358

@@ -155,6 +160,12 @@ if (ENVIRONMENT_IS_WASM_WORKER) {
155160
#endif
156161
'sb': stackLowestAddress, // sb = stack bottom (lowest stack address, SP points at this when stack is full)
157162
'sz': stackSize, // sz = stack size
163+
#if USE_OFFSET_CONVERTER
164+
'wasmOffsetData': wasmOffsetConverter,
165+
#endif
166+
#if LOAD_SOURCE_MAP
167+
'wasmSourceMapData': wasmSourceMap,
168+
#endif
158169
});
159170
worker.onmessage = _wasmWorkerRunPostMessage;
160171
return _wasmWorkersID++;

src/parseTools.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,18 @@ function runIfMainThread(text) {
736736
}
737737
}
738738

739+
function runIfWorkerThread(text) {
740+
if (WASM_WORKERS && PTHREADS) {
741+
return 'if (ENVIRONMENT_IS_WASM_WORKER || ENVIRONMENT_IS_PTHREAD) { ' + text + ' }';
742+
} else if (WASM_WORKERS) {
743+
return 'if (ENVIRONMENT_IS_WASM_WORKER) { ' + text + ' }';
744+
} else if (PTHREADS) {
745+
return 'if (ENVIRONMENT_IS_PTHREAD) { ' + text + ' }';
746+
} else {
747+
return '';
748+
}
749+
}
750+
739751
// Legacy name for runIfMainThread.
740752
// TODO(remove).
741753
const runOnMainThread = runIfMainThread;
@@ -1023,3 +1035,7 @@ function getPerformanceNow() {
10231035
return 'performance.now';
10241036
}
10251037
}
1038+
1039+
function implicitSelf() {
1040+
return ENVIRONMENT.includes('node') ? 'self.' : '';
1041+
}

src/preamble.js

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ function instantiateSync(file, info) {
786786
}
787787
#endif
788788

789-
#if PTHREADS && (LOAD_SOURCE_MAP || USE_OFFSET_CONVERTER)
789+
#if SHARED_MEMORY && (LOAD_SOURCE_MAP || USE_OFFSET_CONVERTER)
790790
// When using postMessage to send an object, it is processed by the structured
791791
// clone algorithm. The prototype, and hence methods, on that object is then
792792
// lost. This function adds back the lost prototype. This does not work with
@@ -1035,7 +1035,7 @@ function createWasm() {
10351035
exportWasmSymbols(wasmExports);
10361036
#endif
10371037

1038-
#if PTHREADS || WASM_WORKERS
1038+
#if SHARED_MEMORY
10391039
// We now have the Wasm module loaded up, keep a reference to the compiled module so we can post it to the workers.
10401040
wasmModule = module;
10411041
#endif
@@ -1083,22 +1083,18 @@ function createWasm() {
10831083
// path.
10841084
if (Module['instantiateWasm']) {
10851085

1086-
#if USE_OFFSET_CONVERTER && PTHREADS
1087-
if (ENVIRONMENT_IS_PTHREAD) {
1086+
#if USE_OFFSET_CONVERTER
10881087
#if ASSERTIONS
1089-
assert(Module['wasmOffsetData'], 'wasmOffsetData not found on Module object');
1088+
{{{ runIfWorkerThread("assert(Module['wasmOffsetData'], 'wasmOffsetData not found on Module object');") }}}
10901089
#endif
1091-
wasmOffsetConverter = resetPrototype(WasmOffsetConverter, Module['wasmOffsetData']);
1092-
}
1090+
{{{ runIfWorkerThread("wasmOffsetConverter = resetPrototype(WasmOffsetConverter, Module['wasmOffsetData']);") }}}
10931091
#endif
10941092

1095-
#if LOAD_SOURCE_MAP && PTHREADS
1096-
if (ENVIRONMENT_IS_PTHREAD) {
1093+
#if LOAD_SOURCE_MAP
10971094
#if ASSERTIONS
1098-
assert(Module['wasmSourceMapData'], 'wasmSourceMapData not found on Module object');
1095+
{{{ runIfWorkerThread("assert(Module['wasmSourceMapData'], 'wasmSourceMapData not found on Module object');") }}}
10991096
#endif
1100-
wasmSourceMap = resetPrototype(WasmSourceMap, Module['wasmSourceMapData']);
1101-
}
1097+
{{{ runIfWorkerThread("wasmSourceMap = resetPrototype(WasmSourceMap, Module['wasmSourceMapData']);") }}}
11021098
#endif
11031099

11041100
try {

src/wasm_worker.js

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,51 @@
11
// N.B. The contents of this file are duplicated in src/library_wasm_worker.js
22
// in variable "_wasmWorkerBlobUrl" (where the contents are pre-minified) If
33
// doing any changes to this file, be sure to update the contents there too.
4-
onmessage = function(d) {
4+
5+
'use strict';
6+
7+
#if ENVIRONMENT_MAY_BE_NODE
8+
// Node.js support
9+
var ENVIRONMENT_IS_NODE = typeof process == 'object' && typeof process.versions == 'object' && typeof process.versions.node == 'string';
10+
if (ENVIRONMENT_IS_NODE) {
11+
// Create as web-worker-like an environment as we can.
12+
13+
var nodeWorkerThreads = require('worker_threads');
14+
15+
var parentPort = nodeWorkerThreads.parentPort;
16+
17+
parentPort.on('message', (data) => typeof onmessage === "function" && onmessage({ data: data }));
18+
19+
var fs = require('fs');
20+
21+
Object.assign(global, {
22+
self: global,
23+
require,
24+
location: {
25+
href: __filename
26+
},
27+
Worker: nodeWorkerThreads.Worker,
28+
importScripts: (f) => (0, eval)(fs.readFileSync(f, 'utf8') + '//# sourceURL=' + f),
29+
postMessage: (msg) => parentPort.postMessage(msg),
30+
performance: global.performance || { now: Date.now },
31+
addEventListener: (name, handler) => parentPort.on(name, handler),
32+
removeEventListener: (name, handler) => parentPort.off(name, handler),
33+
});
34+
}
35+
#endif // ENVIRONMENT_MAY_BE_NODE
36+
37+
{{{ implicitSelf() }}}onmessage = function(d) {
538
// The first message sent to the Worker is always the bootstrap message.
639
// Drop this message listener, it served its purpose of bootstrapping
740
// the Wasm Module load, and is no longer needed. Let user code register
841
// any desired message handlers from now on.
9-
onmessage = null;
42+
{{{ implicitSelf() }}}onmessage = null;
1043
d = d.data;
1144
#if !MODULARIZE
1245
self.{{{ EXPORT_NAME }}} = d;
1346
#endif
1447
#if !MINIMAL_RUNTIME
15-
d['instantiateWasm'] = (info, receiveInstance) => { var instance = new WebAssembly.Instance(d['wasm'], info); receiveInstance(instance, d['wasm']); return instance.exports; }
48+
d['instantiateWasm'] = (info, receiveInstance) => { var instance = new WebAssembly.Instance(d['wasm'], info); return receiveInstance(instance, d['wasm']); }
1649
#endif
1750
importScripts(d.js);
1851
#if MODULARIZE

test/test_core.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9838,16 +9838,23 @@ def test_emscripten_async_load_script(self):
98389838
self.run_process([FILE_PACKAGER, 'test.data', '--preload', 'file1.txt', 'file2.txt', '--from-emcc', '--js-output=script2.js'])
98399839
self.do_runf(test_file('test_emscripten_async_load_script.c'), emcc_args=['-sFORCE_FILESYSTEM'])
98409840

9841+
def prep_wasm_worker_in_node(self):
9842+
# Auto exit after 3 seconds in Nodejs environment to get WASM Worker stdout
9843+
self.add_pre_run("setTimeout(()=>process.exit(), 3000);")
9844+
98419845
@node_pthreads
98429846
def test_wasm_worker_hello(self):
9843-
self.do_runf(test_file('wasm_worker/hello_wasm_worker.c'), emcc_args=['-sWASM_WORKERS'])
9847+
self.prep_wasm_worker_in_node()
9848+
self.do_run_in_out_file_test(test_file('wasm_worker/hello_wasm_worker.c'), emcc_args=['-sWASM_WORKERS'])
98449849

98459850
@node_pthreads
98469851
def test_wasm_worker_malloc(self):
9847-
self.do_runf(test_file('wasm_worker/malloc_wasm_worker.c'), emcc_args=['-sWASM_WORKERS'])
9852+
self.prep_wasm_worker_in_node()
9853+
self.do_run_in_out_file_test(test_file('wasm_worker/malloc_wasm_worker.c'), emcc_args=['-sWASM_WORKERS'])
98489854

98499855
@node_pthreads
98509856
def test_wasm_worker_wait_async(self):
9857+
self.prep_wasm_worker_in_node()
98519858
self.do_runf(test_file('wasm_worker/wait_async.c'), emcc_args=['-sWASM_WORKERS'])
98529859

98539860

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello from wasm worker!
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello from wasm worker!

0 commit comments

Comments
 (0)