space-data-module-sdk 0.8.19 → 0.8.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +2 -2
- package/docs/assembly.js +190 -0
- package/docs/browser-wasmedge-isomorphic.html +6 -1
- package/docs/byo-wasm-quickstart.html +6 -1
- package/docs/conformance.html +6 -1
- package/docs/events-abi.html +6 -1
- package/docs/families/analytics.html +7 -2
- package/docs/families/attitude.html +7 -2
- package/docs/families/behavior.html +7 -2
- package/docs/families/breakup.html +7 -2
- package/docs/families/conjunction.html +7 -2
- package/docs/families/data-source.html +7 -2
- package/docs/families/effects.html +7 -2
- package/docs/families/environment.html +7 -2
- package/docs/families/estimation.html +7 -2
- package/docs/families/gnc.html +7 -2
- package/docs/families/maneuver.html +7 -2
- package/docs/families/obstruction.html +7 -2
- package/docs/families/propagator.html +7 -2
- package/docs/families/propulsion.html +7 -2
- package/docs/families/reentry.html +7 -2
- package/docs/families/rf.html +7 -2
- package/docs/families/scheduler.html +7 -2
- package/docs/families/sensor.html +7 -2
- package/docs/families/signature.html +7 -2
- package/docs/flatsql-host-contract.html +7 -2
- package/docs/flatsql-host-contract.md +2 -2
- package/docs/flatsql-streaming-standard.html +6 -1
- package/docs/gpu-module-abi.html +6 -1
- package/docs/index.html +21 -14
- package/docs/isomorphic-pthreads.html +31 -2
- package/docs/isomorphic-pthreads.md +104 -1
- package/docs/isomorphic-sdn-runtime-plan.html +6 -1
- package/docs/language-runtime-matrix.html +6 -1
- package/docs/llms.txt +1 -1
- package/docs/module-bundle-runtime-plan.html +6 -1
- package/docs/module-publication-standard.html +6 -1
- package/docs/node-red-default-node-parity.html +6 -1
- package/docs/protect-and-sign.html +6 -1
- package/docs/protocol-installation.html +6 -1
- package/docs/publication-submission.html +6 -1
- package/docs/secrets-capability.html +6 -1
- package/docs/styles.css +32 -0
- package/docs/testing-harness.html +6 -1
- package/docs/tri-runtime-parity-gate.html +6 -1
- package/docs/tri-runtime-parity.html +6 -1
- package/package.json +1 -1
- package/src/compiler/invokeGlue.js +38 -0
- package/src/host/browserModuleHarness.js +58 -35
- package/src/host/isomorphicLoader.js +21 -6
- package/src/host/wasiShim.js +57 -13
- package/src/host/wasiThreadBrowserWorker.mjs +4 -0
- package/src/host/wasiThreadHost.js +19 -3
- package/src/host/wasiThreadWorker.mjs +25 -2
- package/src/host/wasiThreadWorkerRuntime.js +2 -1
- package/src/index.d.ts +2 -0
- package/src/runtime/constants.js +6 -0
- package/src/testing/browserModuleHarness.js +2 -0
- package/src/testing/buildWasmEdgeRunner.js +147 -4
- package/src/testing/docker/wasmedge-parity.Dockerfile +23 -1
- package/src/testing/isomorphicHarness.js +5 -0
- package/src/testing/native/wasmedge-0.16.4-atomic-wait.patch +111 -0
- package/src/testing/native/wasmedge_wasi_threads_runner.c +353 -0
- package/src/testing/parityBrowserRunner.js +12 -4
- package/src/testing/parityHarness.js +17 -3
- package/src/testing/parityLanes.js +48 -5
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
|
+
<script>try{var t=localStorage.getItem("sdn-theme");if(t==="light"||t==="dark")document.documentElement.setAttribute("data-theme",t)}catch(e){}</script>
|
|
5
6
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
7
|
<meta name="description" content="This repo now includes two related testing/runtime surfaces in" />
|
|
7
8
|
<title>Testing harness — Space Data Module SDK</title>
|
|
8
9
|
<link rel="stylesheet" href="./styles.css" />
|
|
10
|
+
<script src="./assembly.js" defer></script>
|
|
9
11
|
<!-- SDN_CONSUMER_ASSETS_START -->
|
|
10
12
|
<link rel="stylesheet" href="https://static.spacedatanetwork.org/assets/hd-wallet-ui/2.0.28/sdn-wallet-public-client.c3f68d1cfd88478f10d836a5e829d1dfc6a10157972cf0f7d4d319d0636f2cc4.css" integrity="sha384-fICuhN4I9xqOK1F5vGGzl26opuO+xQIvTZXMSV76lWTBiQ6AfzztMGLLDw8yRT8i" crossorigin="anonymous">
|
|
11
13
|
<script defer src="https://static.spacedatanetwork.org/assets/hd-wallet-ui/2.0.28/sdn-wallet-public-client.f611e7e151a3b5c38384272f8894a4c6634f0a29bf925b0e02e0e27f8db0bfff.js" integrity="sha384-R+QqsKoWJIS7iWrtPmgJ49DVnb1hSGjZokupbLInJd1PLp8RwQhtF/hnaerc33ci" crossorigin="anonymous" data-sdn-wallet-public-client="v1"></script>
|
|
@@ -13,6 +15,7 @@
|
|
|
13
15
|
<!-- SDN_CONSUMER_ASSETS_END -->
|
|
14
16
|
</head>
|
|
15
17
|
<body>
|
|
18
|
+
<canvas id="assembly" aria-hidden="true"></canvas>
|
|
16
19
|
<a class="skip-link" href="#main">Skip to content</a>
|
|
17
20
|
<sdn-stack-nav active="module-sdk"></sdn-stack-nav>
|
|
18
21
|
<header class="site-header">
|
|
@@ -22,12 +25,13 @@
|
|
|
22
25
|
<a href="./conformance.html">Conformance</a>
|
|
23
26
|
<a href="https://github.com/DigitalArsenal/space-data-module-sdk">GitHub</a>
|
|
24
27
|
<a class="stack-button" href="#stack">Stack</a>
|
|
28
|
+
<button class="theme-toggle" type="button" aria-label="Switch between light and dark theme" title="Light or dark theme"><svg class="sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg><svg class="moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 14.5A8 8 0 0 1 9.5 4a8 8 0 1 0 10.5 10.5z"/></svg></button>
|
|
25
29
|
</nav>
|
|
26
30
|
</header>
|
|
27
31
|
<div class="shell">
|
|
28
32
|
<nav class="sidebar" id="sidebar" aria-label="Documentation">
|
|
29
33
|
<h2>Start here</h2><ul>
|
|
30
|
-
<li><a href="./index.html"><span>
|
|
34
|
+
<li><a href="./index.html"><span>Module types</span></a></li>
|
|
31
35
|
<li><a href="./byo-wasm-quickstart.html"><span>BYO-wasm quickstart</span></a></li>
|
|
32
36
|
<li><a href="./conformance.html"><span>Conformance kit</span></a></li>
|
|
33
37
|
<li><a href="./protect-and-sign.html"><span>Protect and sign</span></a></li>
|
|
@@ -403,6 +407,7 @@ npm run benchmark:module-stream-1gib</code></pre></div>
|
|
|
403
407
|
<footer class="site-footer">
|
|
404
408
|
Space Data Module SDK — Apache-2.0. Every ABI page renders a Markdown
|
|
405
409
|
source in <code>docs/</code>; edit the Markdown, never the HTML.
|
|
410
|
+
Contact <a href="mailto:tj@edgesource.com">tj@edgesource.com</a>.
|
|
406
411
|
</footer>
|
|
407
412
|
</body>
|
|
408
413
|
</html>
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
|
+
<script>try{var t=localStorage.getItem("sdn-theme");if(t==="light"||t==="dark")document.documentElement.setAttribute("data-theme",t)}catch(e){}</script>
|
|
5
6
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
7
|
<meta name="description" content="docs/tri-runtime-parity.md describes the parity harness: one" />
|
|
7
8
|
<title>Tri-runtime parity gate — Space Data Module SDK</title>
|
|
8
9
|
<link rel="stylesheet" href="./styles.css" />
|
|
10
|
+
<script src="./assembly.js" defer></script>
|
|
9
11
|
<!-- SDN_CONSUMER_ASSETS_START -->
|
|
10
12
|
<link rel="stylesheet" href="https://static.spacedatanetwork.org/assets/hd-wallet-ui/2.0.28/sdn-wallet-public-client.c3f68d1cfd88478f10d836a5e829d1dfc6a10157972cf0f7d4d319d0636f2cc4.css" integrity="sha384-fICuhN4I9xqOK1F5vGGzl26opuO+xQIvTZXMSV76lWTBiQ6AfzztMGLLDw8yRT8i" crossorigin="anonymous">
|
|
11
13
|
<script defer src="https://static.spacedatanetwork.org/assets/hd-wallet-ui/2.0.28/sdn-wallet-public-client.f611e7e151a3b5c38384272f8894a4c6634f0a29bf925b0e02e0e27f8db0bfff.js" integrity="sha384-R+QqsKoWJIS7iWrtPmgJ49DVnb1hSGjZokupbLInJd1PLp8RwQhtF/hnaerc33ci" crossorigin="anonymous" data-sdn-wallet-public-client="v1"></script>
|
|
@@ -13,6 +15,7 @@
|
|
|
13
15
|
<!-- SDN_CONSUMER_ASSETS_END -->
|
|
14
16
|
</head>
|
|
15
17
|
<body>
|
|
18
|
+
<canvas id="assembly" aria-hidden="true"></canvas>
|
|
16
19
|
<a class="skip-link" href="#main">Skip to content</a>
|
|
17
20
|
<sdn-stack-nav active="module-sdk"></sdn-stack-nav>
|
|
18
21
|
<header class="site-header">
|
|
@@ -22,12 +25,13 @@
|
|
|
22
25
|
<a href="./conformance.html">Conformance</a>
|
|
23
26
|
<a href="https://github.com/DigitalArsenal/space-data-module-sdk">GitHub</a>
|
|
24
27
|
<a class="stack-button" href="#stack">Stack</a>
|
|
28
|
+
<button class="theme-toggle" type="button" aria-label="Switch between light and dark theme" title="Light or dark theme"><svg class="sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg><svg class="moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 14.5A8 8 0 0 1 9.5 4a8 8 0 1 0 10.5 10.5z"/></svg></button>
|
|
25
29
|
</nav>
|
|
26
30
|
</header>
|
|
27
31
|
<div class="shell">
|
|
28
32
|
<nav class="sidebar" id="sidebar" aria-label="Documentation">
|
|
29
33
|
<h2>Start here</h2><ul>
|
|
30
|
-
<li><a href="./index.html"><span>
|
|
34
|
+
<li><a href="./index.html"><span>Module types</span></a></li>
|
|
31
35
|
<li><a href="./byo-wasm-quickstart.html"><span>BYO-wasm quickstart</span></a></li>
|
|
32
36
|
<li><a href="./conformance.html"><span>Conformance kit</span></a></li>
|
|
33
37
|
<li><a href="./protect-and-sign.html"><span>Protect and sign</span></a></li>
|
|
@@ -177,6 +181,7 @@ space-data-module parity-gate --gate-manifest ./parity/negative-control.json --e
|
|
|
177
181
|
<footer class="site-footer">
|
|
178
182
|
Space Data Module SDK — Apache-2.0. Every ABI page renders a Markdown
|
|
179
183
|
source in <code>docs/</code>; edit the Markdown, never the HTML.
|
|
184
|
+
Contact <a href="mailto:tj@edgesource.com">tj@edgesource.com</a>.
|
|
180
185
|
</footer>
|
|
181
186
|
</body>
|
|
182
187
|
</html>
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
|
+
<script>try{var t=localStorage.getItem("sdn-theme");if(t==="light"||t==="dark")document.documentElement.setAttribute("data-theme",t)}catch(e){}</script>
|
|
5
6
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
7
|
<meta name="description" content="ONE dist/isomorphic/module.wasm, THREE runtimes, IDENTICAL behavior:" />
|
|
7
8
|
<title>Tri-runtime parity — Space Data Module SDK</title>
|
|
8
9
|
<link rel="stylesheet" href="./styles.css" />
|
|
10
|
+
<script src="./assembly.js" defer></script>
|
|
9
11
|
<!-- SDN_CONSUMER_ASSETS_START -->
|
|
10
12
|
<link rel="stylesheet" href="https://static.spacedatanetwork.org/assets/hd-wallet-ui/2.0.28/sdn-wallet-public-client.c3f68d1cfd88478f10d836a5e829d1dfc6a10157972cf0f7d4d319d0636f2cc4.css" integrity="sha384-fICuhN4I9xqOK1F5vGGzl26opuO+xQIvTZXMSV76lWTBiQ6AfzztMGLLDw8yRT8i" crossorigin="anonymous">
|
|
11
13
|
<script defer src="https://static.spacedatanetwork.org/assets/hd-wallet-ui/2.0.28/sdn-wallet-public-client.f611e7e151a3b5c38384272f8894a4c6634f0a29bf925b0e02e0e27f8db0bfff.js" integrity="sha384-R+QqsKoWJIS7iWrtPmgJ49DVnb1hSGjZokupbLInJd1PLp8RwQhtF/hnaerc33ci" crossorigin="anonymous" data-sdn-wallet-public-client="v1"></script>
|
|
@@ -13,6 +15,7 @@
|
|
|
13
15
|
<!-- SDN_CONSUMER_ASSETS_END -->
|
|
14
16
|
</head>
|
|
15
17
|
<body>
|
|
18
|
+
<canvas id="assembly" aria-hidden="true"></canvas>
|
|
16
19
|
<a class="skip-link" href="#main">Skip to content</a>
|
|
17
20
|
<sdn-stack-nav active="module-sdk"></sdn-stack-nav>
|
|
18
21
|
<header class="site-header">
|
|
@@ -22,12 +25,13 @@
|
|
|
22
25
|
<a href="./conformance.html">Conformance</a>
|
|
23
26
|
<a href="https://github.com/DigitalArsenal/space-data-module-sdk">GitHub</a>
|
|
24
27
|
<a class="stack-button" href="#stack">Stack</a>
|
|
28
|
+
<button class="theme-toggle" type="button" aria-label="Switch between light and dark theme" title="Light or dark theme"><svg class="sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg><svg class="moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 14.5A8 8 0 0 1 9.5 4a8 8 0 1 0 10.5 10.5z"/></svg></button>
|
|
25
29
|
</nav>
|
|
26
30
|
</header>
|
|
27
31
|
<div class="shell">
|
|
28
32
|
<nav class="sidebar" id="sidebar" aria-label="Documentation">
|
|
29
33
|
<h2>Start here</h2><ul>
|
|
30
|
-
<li><a href="./index.html"><span>
|
|
34
|
+
<li><a href="./index.html"><span>Module types</span></a></li>
|
|
31
35
|
<li><a href="./byo-wasm-quickstart.html"><span>BYO-wasm quickstart</span></a></li>
|
|
32
36
|
<li><a href="./conformance.html"><span>Conformance kit</span></a></li>
|
|
33
37
|
<li><a href="./protect-and-sign.html"><span>Protect and sign</span></a></li>
|
|
@@ -198,6 +202,7 @@
|
|
|
198
202
|
<footer class="site-footer">
|
|
199
203
|
Space Data Module SDK — Apache-2.0. Every ABI page renders a Markdown
|
|
200
204
|
source in <code>docs/</code>; edit the Markdown, never the HTML.
|
|
205
|
+
Contact <a href="mailto:tj@edgesource.com">tj@edgesource.com</a>.
|
|
201
206
|
</footer>
|
|
202
207
|
</body>
|
|
203
208
|
</html>
|
package/package.json
CHANGED
|
@@ -302,6 +302,43 @@ function renderMethodDescriptors(methods) {
|
|
|
302
302
|
.join("\n");
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
+
// Direct-surface initializer for command-model artifacts (wasi toolchains).
|
|
306
|
+
//
|
|
307
|
+
// A command artifact links crt1-command: its _start sets up the main-thread
|
|
308
|
+
// descriptor (__wasi_init_tp, threads sysroot) and runs the global
|
|
309
|
+
// constructors, then main. A host that serves the direct surface never enters
|
|
310
|
+
// _start, so without this entry namespace-scope C++ objects stay zero-filled
|
|
311
|
+
// and the main thread has no pthread descriptor. It is exported under the
|
|
312
|
+
// conventional __wasm_call_ctors name that direct hosts call when a module has
|
|
313
|
+
// no reactor _initialize. It runs once per instance and is a no-op on an
|
|
314
|
+
// instance whose constructors have already run.
|
|
315
|
+
const COMMAND_DIRECT_INITIALIZER_SOURCE = `#if defined(__wasi__)
|
|
316
|
+
extern "C" void __wasm_call_ctors(void);
|
|
317
|
+
extern "C" __attribute__((weak)) void __wasi_init_tp(void);
|
|
318
|
+
|
|
319
|
+
namespace {
|
|
320
|
+
// volatile: the optimizer would otherwise evaluate the marking constructor at
|
|
321
|
+
// compile time and emit the flag as already set.
|
|
322
|
+
volatile int g_sdm_constructors_ran = 0;
|
|
323
|
+
|
|
324
|
+
__attribute__((constructor)) void MarkConstructorsRan() {
|
|
325
|
+
__atomic_store_n(&g_sdm_constructors_ran, 1, __ATOMIC_SEQ_CST);
|
|
326
|
+
}
|
|
327
|
+
} // namespace
|
|
328
|
+
|
|
329
|
+
extern "C" __attribute__((export_name("__wasm_call_ctors")))
|
|
330
|
+
void sdm_command_direct_initialize(void) {
|
|
331
|
+
if (__atomic_exchange_n(&g_sdm_constructors_ran, 1, __ATOMIC_SEQ_CST) != 0) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
if (__wasi_init_tp) {
|
|
335
|
+
__wasi_init_tp();
|
|
336
|
+
}
|
|
337
|
+
__wasm_call_ctors();
|
|
338
|
+
}
|
|
339
|
+
#endif
|
|
340
|
+
`;
|
|
341
|
+
|
|
305
342
|
export function generateInvokeSupportSource({ manifest = {}, includeCommandMain = true } = {}) {
|
|
306
343
|
const methods = Array.isArray(manifest.methods) ? manifest.methods : [];
|
|
307
344
|
return `#include <algorithm>
|
|
@@ -1812,6 +1849,7 @@ extern "C" uint32_t plugin_invoke_stream(
|
|
|
1812
1849
|
return response_ptr;
|
|
1813
1850
|
}
|
|
1814
1851
|
|
|
1852
|
+
${includeCommandMain ? COMMAND_DIRECT_INITIALIZER_SOURCE : ""}
|
|
1815
1853
|
${includeCommandMain
|
|
1816
1854
|
? `int main(int argc, char **argv) {
|
|
1817
1855
|
const char *shortcut_method = nullptr;
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* stdout for the response bytes.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
import { createBrowserWasiShim, WasiExitError } from "./wasiShim.js";
|
|
23
|
+
import { createBrowserWasiShim, createSharedWasiProcess, WasiExitError } from "./wasiShim.js";
|
|
24
24
|
import {
|
|
25
25
|
createWasiThreadSpawn,
|
|
26
26
|
isWasiThreadsModule,
|
|
@@ -297,6 +297,28 @@ function resolveManifestSurface(manifest) {
|
|
|
297
297
|
return null;
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
+
// Run the module's initializer, once per instance, before any direct call.
|
|
301
|
+
// A reactor exports `_initialize` (constructors + WASI init) and runs it on
|
|
302
|
+
// every instance, as before. A command artifact runs its constructors inside
|
|
303
|
+
// `_start`, which then runs main and consumes stdin, so a command instance
|
|
304
|
+
// only ever enters `_start`. An instance that serves the DIRECT surface of a
|
|
305
|
+
// command artifact runs the artifact's `__wasm_call_ctors` export instead:
|
|
306
|
+
// constructors (and main-thread setup) without main. Artifacts built before
|
|
307
|
+
// that export existed have no constructor entry a host can call without main;
|
|
308
|
+
// their direct surface stays uninitialized in every runtime alike.
|
|
309
|
+
function initializeInstance(instance, directSurface) {
|
|
310
|
+
const exports = instance.exports;
|
|
311
|
+
const reactorInitialize = exports[DefaultInvokeExports.reactorInitializeSymbol];
|
|
312
|
+
if (typeof reactorInitialize === "function") {
|
|
313
|
+
reactorInitialize();
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
const constructors = exports[DefaultInvokeExports.constructorsSymbol];
|
|
317
|
+
if (directSurface && typeof constructors === "function") {
|
|
318
|
+
constructors();
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
300
322
|
async function instantiateBrowserModule(options = {}) {
|
|
301
323
|
let providedMemory = options.wasmMemory ?? options.memory ?? null;
|
|
302
324
|
if (
|
|
@@ -307,7 +329,10 @@ async function instantiateBrowserModule(options = {}) {
|
|
|
307
329
|
"Browser module harness memory must be a WebAssembly.Memory.",
|
|
308
330
|
);
|
|
309
331
|
}
|
|
332
|
+
const isThreaded = isWasiThreadsModule(options.wasmModule);
|
|
333
|
+
const processState = isThreaded ? createSharedWasiProcess(options) : null;
|
|
310
334
|
const wasi = createBrowserWasiShim({
|
|
335
|
+
processState,
|
|
311
336
|
args: options.args ?? [],
|
|
312
337
|
env: options.env ?? {},
|
|
313
338
|
stdinBytes: options.stdinBytes ?? new Uint8Array(),
|
|
@@ -323,7 +348,6 @@ async function instantiateBrowserModule(options = {}) {
|
|
|
323
348
|
// `wasi.thread-spawn` over a SHARED imported memory. Such a module can only be
|
|
324
349
|
// instantiated with shared memory, so force it here regardless of the caller's
|
|
325
350
|
// sharedMemory flag; single-thread artifacts are unaffected.
|
|
326
|
-
const isThreaded = isWasiThreadsModule(options.wasmModule);
|
|
327
351
|
const memoryImports = moduleImports.filter((entry) => entry.kind === "memory");
|
|
328
352
|
if (!providedMemory && memoryImports.length > 0) {
|
|
329
353
|
providedMemory = createImportedMemory(
|
|
@@ -356,6 +380,7 @@ async function instantiateBrowserModule(options = {}) {
|
|
|
356
380
|
threadHost = await createWasiThreadSpawn({
|
|
357
381
|
wasmModule: options.wasmModule,
|
|
358
382
|
memory: providedMemory,
|
|
383
|
+
processState,
|
|
359
384
|
// Browser warm-pool sizing: cap pooled workers at how many guest threads
|
|
360
385
|
// the module will actually ask for. Ignored by the Node lazy path.
|
|
361
386
|
requestedThreads: options.maxThreads,
|
|
@@ -395,35 +420,24 @@ async function instantiateBrowserModule(options = {}) {
|
|
|
395
420
|
Object.assign(importObject, bridge.imports);
|
|
396
421
|
}
|
|
397
422
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
if (
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
wasi.setMemory(memory);
|
|
410
|
-
}
|
|
411
|
-
if (instance.exports._initialize) {
|
|
412
|
-
instance.exports._initialize();
|
|
413
|
-
} else if (isThreaded && typeof instance.exports._start === "function") {
|
|
414
|
-
// wasi-threads artifacts link the wasi command crt (exports `_start`), not a
|
|
415
|
-
// reactor (`_initialize`). Run `_start` ONCE to execute global constructors
|
|
416
|
-
// + WASI init before any direct invoke. The module declares no command
|
|
417
|
-
// surface, so its main is an empty stub — `_start` runs ctors and proc_exit's
|
|
418
|
-
// out; swallow that exit. Direct-invoke exports remain callable afterward
|
|
419
|
-
// (the linear memory + globals persist).
|
|
420
|
-
try {
|
|
421
|
-
instance.exports._start();
|
|
422
|
-
} catch (error) {
|
|
423
|
-
if (!(error instanceof WasiExitError)) {
|
|
424
|
-
throw error;
|
|
423
|
+
try {
|
|
424
|
+
instance = await WebAssembly.instantiate(options.wasmModule, importObject);
|
|
425
|
+
memory = instance.exports.memory ?? providedMemory;
|
|
426
|
+
if (memory) {
|
|
427
|
+
if (
|
|
428
|
+
options.sharedMemory === true &&
|
|
429
|
+
!isSharedArrayBufferLike(memory.buffer)
|
|
430
|
+
) {
|
|
431
|
+
throw new Error(
|
|
432
|
+
"Browser module harness sharedMemory requires shared WebAssembly.Memory backing.",
|
|
433
|
+
);
|
|
425
434
|
}
|
|
435
|
+
wasi.setMemory(memory);
|
|
426
436
|
}
|
|
437
|
+
initializeInstance(instance, options.directSurface === true);
|
|
438
|
+
} catch (error) {
|
|
439
|
+
await threadHost?.terminateAll();
|
|
440
|
+
throw error;
|
|
427
441
|
}
|
|
428
442
|
|
|
429
443
|
return {
|
|
@@ -547,6 +561,7 @@ export async function createBrowserModuleHarness(options = {}) {
|
|
|
547
561
|
|
|
548
562
|
const activeContext = await instantiateBrowserModule({
|
|
549
563
|
wasmModule,
|
|
564
|
+
directSurface: surface === "direct",
|
|
550
565
|
host,
|
|
551
566
|
hostcallDispatch: options.hostcallDispatch,
|
|
552
567
|
args: options.args,
|
|
@@ -561,8 +576,11 @@ export async function createBrowserModuleHarness(options = {}) {
|
|
|
561
576
|
maxThreads: options.maxThreads,
|
|
562
577
|
threadHostcallChannel: options.threadHostcallChannel,
|
|
563
578
|
enableBrowserWasiThreads: options.enableBrowserWasiThreads,
|
|
579
|
+
wasiThreadWorkerBaseUrl: options.wasiThreadWorkerBaseUrl,
|
|
580
|
+
wasiThreadWorkerUrl: options.wasiThreadWorkerUrl,
|
|
564
581
|
});
|
|
565
582
|
const { instance, bridge, wasi, memory, threadHost } = activeContext;
|
|
583
|
+
let lastCommandContext = null;
|
|
566
584
|
const allowRawInvoke = options.allowRawInvoke !== false;
|
|
567
585
|
|
|
568
586
|
// --- Invoke helpers ---
|
|
@@ -805,6 +823,8 @@ export async function createBrowserModuleHarness(options = {}) {
|
|
|
805
823
|
async function invokeCommandRaw(stdinBytes) {
|
|
806
824
|
const commandContext = await instantiateBrowserModule({
|
|
807
825
|
wasmModule,
|
|
826
|
+
// Command CRT startup consumes stdin and is not reentrant. Run it only
|
|
827
|
+
// below, after this fresh instance has received the actual request.
|
|
808
828
|
host,
|
|
809
829
|
hostcallDispatch: options.hostcallDispatch,
|
|
810
830
|
args: options.args,
|
|
@@ -820,7 +840,10 @@ export async function createBrowserModuleHarness(options = {}) {
|
|
|
820
840
|
maxThreads: options.maxThreads,
|
|
821
841
|
threadHostcallChannel: options.threadHostcallChannel,
|
|
822
842
|
enableBrowserWasiThreads: options.enableBrowserWasiThreads,
|
|
843
|
+
wasiThreadWorkerBaseUrl: options.wasiThreadWorkerBaseUrl,
|
|
844
|
+
wasiThreadWorkerUrl: options.wasiThreadWorkerUrl,
|
|
823
845
|
});
|
|
846
|
+
lastCommandContext = commandContext;
|
|
824
847
|
try {
|
|
825
848
|
const commandExport = commandContext.instance.exports[DefaultInvokeExports.commandSymbol];
|
|
826
849
|
if (typeof commandExport !== "function") {
|
|
@@ -833,6 +856,8 @@ export async function createBrowserModuleHarness(options = {}) {
|
|
|
833
856
|
if (!(error instanceof WasiExitError) || error.code !== 0) {
|
|
834
857
|
throw error;
|
|
835
858
|
}
|
|
859
|
+
} finally {
|
|
860
|
+
await commandContext.threadHost?.terminateAll();
|
|
836
861
|
}
|
|
837
862
|
return commandContext.wasi.stdout;
|
|
838
863
|
}
|
|
@@ -903,11 +928,9 @@ export async function createBrowserModuleHarness(options = {}) {
|
|
|
903
928
|
return new Uint8Array(memory.buffer, ptr, size).slice();
|
|
904
929
|
}
|
|
905
930
|
|
|
906
|
-
function destroy() {
|
|
931
|
+
async function destroy() {
|
|
907
932
|
wasi.flushOutput();
|
|
908
|
-
|
|
909
|
-
void threadHost.terminateAll();
|
|
910
|
-
}
|
|
933
|
+
await threadHost?.terminateAll();
|
|
911
934
|
}
|
|
912
935
|
|
|
913
936
|
return {
|
|
@@ -920,12 +943,12 @@ export async function createBrowserModuleHarness(options = {}) {
|
|
|
920
943
|
module: wasmModule,
|
|
921
944
|
host,
|
|
922
945
|
bridge,
|
|
923
|
-
wasi,
|
|
946
|
+
get wasi() { return lastCommandContext?.wasi ?? wasi; },
|
|
924
947
|
memory,
|
|
925
948
|
// Present only for isomorphic-pthreads (wasi-threads) artifacts: exposes the
|
|
926
949
|
// spawn host so callers can observe real thread activity
|
|
927
950
|
// (spawnCount/distinctOsThreadCount).
|
|
928
|
-
threadHost,
|
|
951
|
+
get threadHost() { return lastCommandContext?.threadHost ?? threadHost; },
|
|
929
952
|
callHost,
|
|
930
953
|
invokeDirect,
|
|
931
954
|
invoke,
|
|
@@ -65,12 +65,25 @@ async function createWasmEdgeCommandHarness(options = {}) {
|
|
|
65
65
|
const loadableBytes = toLoadableWasmBytes(wasmBytes);
|
|
66
66
|
const inspection = await inspectModule(loadableBytes);
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
const threaded = inspection.imports.some((entry) =>
|
|
69
|
+
entry.module === "wasi" && entry.name === "thread-spawn");
|
|
70
|
+
const hasCommand = inspection.exports.includes(DefaultInvokeExports.commandSymbol);
|
|
71
|
+
const hasDirect = inspection.exports.includes(DefaultInvokeExports.invokeSymbol);
|
|
72
|
+
// The one-shot wasi-threads runner serves the direct surface of a reactor,
|
|
73
|
+
// and of a command artifact when the caller asks for it (--sdm-direct): the
|
|
74
|
+
// module's constructors then run through its initializer export, never main.
|
|
75
|
+
const surface = hasCommand && !(options.surface === "direct" && threaded && hasDirect)
|
|
76
|
+
? "command"
|
|
77
|
+
: "direct";
|
|
78
|
+
if (surface === "direct" && (!threaded || !hasDirect)) {
|
|
69
79
|
throw new Error(
|
|
70
80
|
"Standalone WasmEdge loading requires a command-surface artifact with the _start export.",
|
|
71
81
|
);
|
|
72
82
|
}
|
|
73
83
|
|
|
84
|
+
const command = threaded
|
|
85
|
+
? await (await import("../testing/buildWasmEdgeRunner.js")).resolveWasmEdgeWasiThreadsRunner(options)
|
|
86
|
+
: options.wasmEdgeRunnerBinary ?? options.wasmEdgeBinary ?? "wasmedge";
|
|
74
87
|
let launchWasmPath = wasmPath;
|
|
75
88
|
let tempArtifactDir = null;
|
|
76
89
|
if (loadableBytes.byteLength !== wasmBytes.byteLength) {
|
|
@@ -84,9 +97,10 @@ async function createWasmEdgeCommandHarness(options = {}) {
|
|
|
84
97
|
await writeFile(launchWasmPath, loadableBytes);
|
|
85
98
|
}
|
|
86
99
|
|
|
87
|
-
const command = options.wasmEdgeBinary ?? "wasmedge";
|
|
88
100
|
const args = [
|
|
101
|
+
...(surface === "direct" && hasCommand ? ["--sdm-direct"] : []),
|
|
89
102
|
...(options.enableThreads === false ? [] : ["--enable-threads"]),
|
|
103
|
+
...Object.entries(options.env ?? {}).flatMap(([key, value]) => ["--env", `${key}=${value}`]),
|
|
90
104
|
launchWasmPath,
|
|
91
105
|
...(Array.isArray(options.args) ? options.args : []),
|
|
92
106
|
];
|
|
@@ -156,7 +170,7 @@ async function createWasmEdgeCommandHarness(options = {}) {
|
|
|
156
170
|
runtime: {
|
|
157
171
|
kind: "wasmedge",
|
|
158
172
|
profile: inspection.profile,
|
|
159
|
-
surface
|
|
173
|
+
surface,
|
|
160
174
|
},
|
|
161
175
|
launchPlan,
|
|
162
176
|
invokeRaw,
|
|
@@ -225,8 +239,7 @@ export async function loadModule(options = {}) {
|
|
|
225
239
|
// byte-level question.
|
|
226
240
|
const needsCompiledModule =
|
|
227
241
|
runtimeKind === "wasmedge" &&
|
|
228
|
-
!runtimeHostRequested
|
|
229
|
-
!options.wasmEdgeRunnerBinary;
|
|
242
|
+
!runtimeHostRequested;
|
|
230
243
|
const needsBytes = Boolean(signaturePolicy) || runtimeKind === "wasmedge";
|
|
231
244
|
let artifactBytes = null;
|
|
232
245
|
let wasmModule = null;
|
|
@@ -264,9 +277,11 @@ export async function loadModule(options = {}) {
|
|
|
264
277
|
});
|
|
265
278
|
if (needsCompiledModule) {
|
|
266
279
|
const inspection = await inspectModule(wasmModule);
|
|
280
|
+
const threaded = inspection.imports.some((entry) => entry.module === "wasi" && entry.name === "thread-spawn");
|
|
267
281
|
if (
|
|
268
282
|
(inspection.profile === "standalone" || inspection.profile === "module-host-abi") &&
|
|
269
|
-
inspection.exports.includes("_start")
|
|
283
|
+
(inspection.exports.includes("_start") || (threaded && inspection.exports.includes("plugin_invoke_stream"))) &&
|
|
284
|
+
(!options.wasmEdgeRunnerBinary || options.surface === "command" || threaded)
|
|
270
285
|
) {
|
|
271
286
|
return attachHostDispatch(
|
|
272
287
|
await createWasmEdgeCommandHarness(options),
|
package/src/host/wasiShim.js
CHANGED
|
@@ -34,10 +34,34 @@ export class WasiExitError extends Error {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
// One process owns its descriptors, even when libc executes main on a pthread.
|
|
38
|
+
// Offsets are atomically reserved so concurrent readers/writers never duplicate
|
|
39
|
+
// input or overwrite another thread's output. Overflow is an explicit WASI error.
|
|
40
|
+
export function createSharedWasiProcess({ args = [], env = {}, stdinBytes = [], maxOutputBytes = 16 * 1024 * 1024 } = {}) {
|
|
41
|
+
const bytes = new Uint8Array(stdinBytes);
|
|
42
|
+
const input = new Uint8Array(new SharedArrayBuffer(bytes.length));
|
|
43
|
+
input.set(bytes);
|
|
44
|
+
return {
|
|
45
|
+
args, env, input,
|
|
46
|
+
control: new Int32Array(new SharedArrayBuffer(5 * 4)),
|
|
47
|
+
stdout: new Uint8Array(new SharedArrayBuffer(maxOutputBytes)),
|
|
48
|
+
stderr: new Uint8Array(new SharedArrayBuffer(maxOutputBytes)),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function reserve(control, index, length, capacity) {
|
|
53
|
+
for (;;) {
|
|
54
|
+
const offset = Atomics.load(control, index);
|
|
55
|
+
if (length > capacity - offset) return -1;
|
|
56
|
+
if (Atomics.compareExchange(control, index, offset, offset + length) === offset) return offset;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
37
60
|
export function createBrowserWasiShim(options = {}) {
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const
|
|
61
|
+
const shared = options.processState;
|
|
62
|
+
const args = shared?.args ?? options.args ?? [];
|
|
63
|
+
const env = shared?.env ?? options.env ?? {};
|
|
64
|
+
const stdinBytes = shared?.input ?? new Uint8Array(options.stdinBytes ?? []);
|
|
41
65
|
const logOutput = options.logOutput === true;
|
|
42
66
|
const performanceApi = options.performance ?? globalThis.performance ?? {
|
|
43
67
|
now: () => Date.now(),
|
|
@@ -100,7 +124,14 @@ export function createBrowserWasiShim(options = {}) {
|
|
|
100
124
|
const base = iovsPtr + i * 8;
|
|
101
125
|
const ptr = dv.getUint32(base, true);
|
|
102
126
|
const len = dv.getUint32(base + 4, true);
|
|
103
|
-
|
|
127
|
+
if (shared) {
|
|
128
|
+
const output = fd === 1 ? shared.stdout : shared.stderr;
|
|
129
|
+
const offset = reserve(shared.control, fd, len, output.length);
|
|
130
|
+
if (offset < 0) return 51; // NOSPC: never silently truncate command output.
|
|
131
|
+
output.set(bytes.subarray(ptr, ptr + len), offset);
|
|
132
|
+
} else {
|
|
133
|
+
target.push(bytes.slice(ptr, ptr + len));
|
|
134
|
+
}
|
|
104
135
|
totalWritten += len;
|
|
105
136
|
}
|
|
106
137
|
|
|
@@ -119,16 +150,25 @@ export function createBrowserWasiShim(options = {}) {
|
|
|
119
150
|
let totalRead = 0;
|
|
120
151
|
|
|
121
152
|
for (let i = 0; i < iovsLen; i += 1) {
|
|
122
|
-
if (stdinOffset >= stdinBytes.length) {
|
|
123
|
-
break;
|
|
124
|
-
}
|
|
125
153
|
const base = iovsPtr + i * 8;
|
|
126
154
|
const ptr = dv.getUint32(base, true);
|
|
127
155
|
const len = dv.getUint32(base + 4, true);
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
156
|
+
let offset, count;
|
|
157
|
+
if (shared) {
|
|
158
|
+
do {
|
|
159
|
+
offset = Atomics.load(shared.control, 0);
|
|
160
|
+
count = Math.min(len, stdinBytes.length - offset);
|
|
161
|
+
} while (Atomics.compareExchange(shared.control, 0, offset, offset + count) !== offset);
|
|
162
|
+
} else {
|
|
163
|
+
offset = stdinOffset;
|
|
164
|
+
count = Math.min(len, stdinBytes.length - offset);
|
|
165
|
+
stdinOffset += count;
|
|
166
|
+
}
|
|
167
|
+
if (count === 0) {
|
|
168
|
+
if (offset >= stdinBytes.length) break;
|
|
169
|
+
continue; // An empty iovec does not mean end of file.
|
|
170
|
+
}
|
|
171
|
+
bytes.set(stdinBytes.subarray(offset, offset + count), ptr);
|
|
132
172
|
totalRead += count;
|
|
133
173
|
}
|
|
134
174
|
|
|
@@ -243,6 +283,10 @@ export function createBrowserWasiShim(options = {}) {
|
|
|
243
283
|
}
|
|
244
284
|
|
|
245
285
|
function proc_exit(code) {
|
|
286
|
+
if (shared) {
|
|
287
|
+
Atomics.store(shared.control, 4, code);
|
|
288
|
+
Atomics.store(shared.control, 3, 1);
|
|
289
|
+
}
|
|
246
290
|
if (logOutput) {
|
|
247
291
|
flushOutput();
|
|
248
292
|
}
|
|
@@ -317,10 +361,10 @@ export function createBrowserWasiShim(options = {}) {
|
|
|
317
361
|
getMemory,
|
|
318
362
|
flushOutput,
|
|
319
363
|
get stdout() {
|
|
320
|
-
return concatChunks(stdoutChunks);
|
|
364
|
+
return shared ? shared.stdout.slice(0, Atomics.load(shared.control, 1)) : concatChunks(stdoutChunks);
|
|
321
365
|
},
|
|
322
366
|
get stderr() {
|
|
323
|
-
return concatChunks(stderrChunks);
|
|
367
|
+
return shared ? shared.stderr.slice(0, Atomics.load(shared.control, 2)) : concatChunks(stderrChunks);
|
|
324
368
|
},
|
|
325
369
|
};
|
|
326
370
|
}
|
|
@@ -16,6 +16,7 @@ self.onmessage = (event) => {
|
|
|
16
16
|
wasmModule,
|
|
17
17
|
memory,
|
|
18
18
|
hostcallChannel,
|
|
19
|
+
processState: message.processState,
|
|
19
20
|
});
|
|
20
21
|
runtime.instantiate();
|
|
21
22
|
self.postMessage({ t: "ready", ok: true });
|
|
@@ -37,6 +38,9 @@ self.onmessage = (event) => {
|
|
|
37
38
|
instance.exports.wasi_thread_start(message.tid, message.startArg);
|
|
38
39
|
} catch (error) {
|
|
39
40
|
if (!(error && error.name === "WasiExitError")) {
|
|
41
|
+
// The thread that joins this one may be blocked in the guest and never
|
|
42
|
+
// handle the message below; report the fault from this worker as well.
|
|
43
|
+
console.error(`[wasi-thread] guest thread ${message.tid} trapped:`, error);
|
|
40
44
|
self.postMessage({
|
|
41
45
|
t: "error",
|
|
42
46
|
tid: message.tid,
|
|
@@ -202,7 +202,7 @@ const BROWSER_POOL_PROBE_TIMEOUT_MS = 1500;
|
|
|
202
202
|
// surfacing) for the life of the pool.
|
|
203
203
|
function armBrowserPool(
|
|
204
204
|
created,
|
|
205
|
-
{ wasmModule, memory, hostcallChannel, timeoutMs, onExit },
|
|
205
|
+
{ wasmModule, memory, hostcallChannel, processState, timeoutMs, onExit },
|
|
206
206
|
) {
|
|
207
207
|
return new Promise((resolve) => {
|
|
208
208
|
let remaining = created.length;
|
|
@@ -266,6 +266,7 @@ function armBrowserPool(
|
|
|
266
266
|
wasmModule,
|
|
267
267
|
memory,
|
|
268
268
|
hostcallChannel: hostcallChannel ?? null,
|
|
269
|
+
processState,
|
|
269
270
|
});
|
|
270
271
|
}
|
|
271
272
|
});
|
|
@@ -333,6 +334,7 @@ export async function createWasiThreadSpawn({
|
|
|
333
334
|
memory,
|
|
334
335
|
requestedThreads,
|
|
335
336
|
hostcallChannel,
|
|
337
|
+
processState,
|
|
336
338
|
requiresHostcalls = false,
|
|
337
339
|
enableBrowserThreads,
|
|
338
340
|
browserWorkerBaseUrl,
|
|
@@ -367,17 +369,29 @@ export async function createWasiThreadSpawn({
|
|
|
367
369
|
);
|
|
368
370
|
const NodeWorker = workerThreads.Worker;
|
|
369
371
|
const nodeWorkerUrl = new URL("./wasiThreadWorker.mjs", import.meta.url);
|
|
372
|
+
// An --input-type parent runs eval/stdin, but this worker loads a file.
|
|
373
|
+
// Inheriting that flag makes the worker fail while the guest is blocked
|
|
374
|
+
// synchronously in pthread_join and cannot receive the error event.
|
|
375
|
+
const parentArgs = globalThis.process.execArgv;
|
|
376
|
+
const sourceFlags = ["--input-type", "--eval", "-e", "--print", "-p"];
|
|
377
|
+
const execArgv = parentArgs.some((arg) => arg.startsWith("--input-type"))
|
|
378
|
+
? parentArgs.filter((arg, index, args) =>
|
|
379
|
+
!sourceFlags.some((flag) => arg === flag || arg.startsWith(`${flag}=`)) &&
|
|
380
|
+
!(index > 0 && sourceFlags.includes(args[index - 1])))
|
|
381
|
+
: undefined;
|
|
370
382
|
|
|
371
383
|
const threadSpawn = (startArg) => {
|
|
372
384
|
const tid = (nextTid += 1);
|
|
373
385
|
try {
|
|
374
386
|
const worker = new NodeWorker(nodeWorkerUrl, {
|
|
387
|
+
execArgv,
|
|
375
388
|
workerData: {
|
|
376
389
|
wasmModule,
|
|
377
390
|
memory,
|
|
378
391
|
tid,
|
|
379
392
|
startArg,
|
|
380
393
|
hostcallChannel: hostcallChannel ?? null,
|
|
394
|
+
processState,
|
|
381
395
|
},
|
|
382
396
|
});
|
|
383
397
|
// Node exposes the OS-thread id per Worker — distinct ids are direct
|
|
@@ -386,8 +400,9 @@ export async function createWasiThreadSpawn({
|
|
|
386
400
|
osThreadIds.add(worker.threadId);
|
|
387
401
|
}
|
|
388
402
|
worker.on("error", (error) => {
|
|
389
|
-
// A worker crash cannot be surfaced to the guest synchronously
|
|
390
|
-
//
|
|
403
|
+
// A worker crash cannot be surfaced to the guest synchronously. The
|
|
404
|
+
// worker itself writes the fault to stderr first, because this
|
|
405
|
+
// handler never runs while this thread is blocked in pthread_join.
|
|
391
406
|
// eslint-disable-next-line no-console
|
|
392
407
|
console.error("[wasi-thread] worker error:", error);
|
|
393
408
|
});
|
|
@@ -491,6 +506,7 @@ export async function createWasiThreadSpawn({
|
|
|
491
506
|
wasmModule,
|
|
492
507
|
memory,
|
|
493
508
|
hostcallChannel,
|
|
509
|
+
processState,
|
|
494
510
|
timeoutMs: BROWSER_POOL_PROBE_TIMEOUT_MS,
|
|
495
511
|
onExit: returnWorkerToIdle,
|
|
496
512
|
});
|