space-data-module-sdk 0.8.24 → 0.8.25
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/docs/isomorphic-pthreads.html +29 -5
- package/docs/isomorphic-pthreads.md +98 -8
- package/package.json +1 -1
- package/src/host/browserModuleHarness.js +13 -0
- package/src/host/hostWorkerBundleSources.js +3 -3
- package/src/host/nodeSyncFsIo.js +3 -1
- package/src/host/wasiThreadBrowserWorker.mjs +41 -21
- package/src/host/wasiThreadHost.js +279 -150
- package/src/host/wasiThreadPool.js +389 -0
- package/src/host/wasiThreadWorker.mjs +62 -20
- package/src/host/wasiThreadWorkerRuntime.js +6 -1
- package/src/index.d.ts +15 -0
- package/src/testing/index.d.ts +2 -0
|
@@ -2,21 +2,50 @@ import {
|
|
|
2
2
|
createWasiThreadWorkerRuntime,
|
|
3
3
|
resolveModuleExtraImports,
|
|
4
4
|
} from "./wasiThreadWorkerRuntime.js";
|
|
5
|
+
import {
|
|
6
|
+
WASI_THREAD_POOL_PROTOCOL,
|
|
7
|
+
createWasiThreadPoolSpawn,
|
|
8
|
+
serveWasiThreadPoolSlot,
|
|
9
|
+
} from "./wasiThreadPool.js";
|
|
5
10
|
|
|
6
|
-
// One pooled browser worker = one guest OS thread. It is pre-started
|
|
7
|
-
// probed by createWasiThreadSpawn (wasiThreadHost.js)
|
|
8
|
-
//
|
|
9
|
-
// as a self-contained classic bundle spawned from a blob: URL (A39,
|
|
11
|
+
// One pooled browser worker = one guest OS thread at a time. It is pre-started
|
|
12
|
+
// and probed by createWasiThreadSpawn (wasiThreadHost.js). The same source
|
|
13
|
+
// ships as a self-contained classic bundle spawned from a blob: URL (A39,
|
|
10
14
|
// hostWorkerBundles.js); nothing here depends on the module-worker form except
|
|
11
15
|
// `{ moduleUrl }` extraImports entries, which need a module worker.
|
|
16
|
+
//
|
|
17
|
+
// With a pool in the probe (SDK 0.8.25), this worker then serves its pool slot
|
|
18
|
+
// (wasiThreadPool.js): it blocks on the slot, runs wasi_thread_start for each
|
|
19
|
+
// thread any guest thread assigns to it, and frees the slot when the thread
|
|
20
|
+
// returns. It never goes back to its event loop, so nothing it does waits for
|
|
21
|
+
// the spawner's. Every guest thread it runs gets the pool's spawn as its
|
|
22
|
+
// wasi.thread-spawn. Without a pool (an older host) it runs {t:"run"} messages
|
|
23
|
+
// and answers each with {t:"exit"}, as before.
|
|
12
24
|
|
|
13
25
|
let runtime = null;
|
|
14
26
|
|
|
27
|
+
function runThread(tid, startArg) {
|
|
28
|
+
try {
|
|
29
|
+
const instance = runtime.instantiate();
|
|
30
|
+
instance.exports.wasi_thread_start(tid, startArg);
|
|
31
|
+
return true;
|
|
32
|
+
} catch (error) {
|
|
33
|
+
if (error && error.name === "WasiExitError") return true;
|
|
34
|
+
// The thread that joins this one may be blocked in the guest and never
|
|
35
|
+
// handle the message below; report the fault from this worker as well.
|
|
36
|
+
console.error(`[wasi-thread] guest thread ${tid} trapped:`, error);
|
|
37
|
+
self.postMessage({ t: "error", tid, error: String(error?.message ?? error) });
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
15
42
|
self.onmessage = async (event) => {
|
|
16
43
|
const message = event.data ?? {};
|
|
17
44
|
if (message.t === "probe") {
|
|
45
|
+
const pool = message.pool ?? null;
|
|
18
46
|
try {
|
|
19
47
|
const extraImports = await resolveModuleExtraImports(message.extraImports ?? []);
|
|
48
|
+
const spawn = pool ? createWasiThreadPoolSpawn(pool) : null;
|
|
20
49
|
runtime = createWasiThreadWorkerRuntime({
|
|
21
50
|
wasmModule: message.wasmModule,
|
|
22
51
|
memory: message.memory,
|
|
@@ -24,9 +53,10 @@ self.onmessage = async (event) => {
|
|
|
24
53
|
processState: message.processState,
|
|
25
54
|
extraImports,
|
|
26
55
|
workerIndex: message.workerIndex,
|
|
56
|
+
threadSpawn: spawn ? (startArg) => spawn(startArg).tid : undefined,
|
|
27
57
|
});
|
|
28
58
|
runtime.instantiate();
|
|
29
|
-
self.postMessage({ t: "ready", ok: true });
|
|
59
|
+
self.postMessage({ t: "ready", ok: true, protocol: WASI_THREAD_POOL_PROTOCOL });
|
|
30
60
|
} catch (error) {
|
|
31
61
|
runtime?.close();
|
|
32
62
|
runtime = null;
|
|
@@ -35,25 +65,15 @@ self.onmessage = async (event) => {
|
|
|
35
65
|
ok: false,
|
|
36
66
|
error: String(error?.message ?? error),
|
|
37
67
|
});
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (pool) {
|
|
71
|
+
// A trapped thread retires the slot and ends the loop.
|
|
72
|
+
serveWasiThreadPoolSlot(pool, message.slot, { runThread });
|
|
38
73
|
}
|
|
39
74
|
return;
|
|
40
75
|
}
|
|
41
76
|
if (message.t !== "run") return;
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
const instance = runtime.instantiate();
|
|
45
|
-
instance.exports.wasi_thread_start(message.tid, message.startArg);
|
|
46
|
-
} catch (error) {
|
|
47
|
-
if (!(error && error.name === "WasiExitError")) {
|
|
48
|
-
// The thread that joins this one may be blocked in the guest and never
|
|
49
|
-
// handle the message below; report the fault from this worker as well.
|
|
50
|
-
console.error(`[wasi-thread] guest thread ${message.tid} trapped:`, error);
|
|
51
|
-
self.postMessage({
|
|
52
|
-
t: "error",
|
|
53
|
-
tid: message.tid,
|
|
54
|
-
error: String(error?.message ?? error),
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
}
|
|
77
|
+
runThread(message.tid, message.startArg);
|
|
58
78
|
self.postMessage({ t: "exit", tid: message.tid });
|
|
59
79
|
};
|