@ai-ecoverse/slicc-kernel 1.45.0 → 1.46.0

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.
@@ -2903,6 +2903,31 @@ function number(r) {
2903
2903
  if (!r.ok) return -wasiErrno(r.errno);
2904
2904
  return r.kind === "json" && typeof r.json === "number" ? r.json : -wasiErrno("EIO");
2905
2905
  }
2906
+ function restarted(issue) {
2907
+ for (; ; ) {
2908
+ const r = issue();
2909
+ if (r.ok || r.errno !== "EINTR") return r;
2910
+ }
2911
+ }
2912
+ function forkRestarted(deps, state, snapshotAt) {
2913
+ let memory = state.memory;
2914
+ let seen = snapshotAt;
2915
+ return restarted(() => {
2916
+ const streams = deps.describeFork();
2917
+ const now = deps.deliveries?.();
2918
+ if (now !== seen) {
2919
+ seen = now;
2920
+ const live = deps.memory?.();
2921
+ if (live) memory = new Uint8Array(live.buffer).slice();
2922
+ }
2923
+ const forked = { ...state, memory, streams, cwd: deps.Fs.cwd() };
2924
+ return deps.transport.call(
2925
+ { op: "proc-fork", state: forked, restart: true },
2926
+ Infinity,
2927
+ "proc-fork"
2928
+ );
2929
+ });
2930
+ }
2906
2931
  function flushed(beforeSpawn) {
2907
2932
  try {
2908
2933
  beforeSpawn();
@@ -3029,20 +3054,18 @@ function createProcessKernel(deps) {
3029
3054
  const promote = deps.stdioPromoter?.();
3030
3055
  const stdio = [0, 1, 2].map((n) => slot(fds[n] ?? -1, n, promote));
3031
3056
  const inherit = deps.inherit?.(actions) ?? [];
3032
- const r = transport.call(
3033
- {
3034
- op: "proc-spawn",
3035
- file,
3036
- argv,
3037
- env: env ?? deps.env,
3038
- cwd: cwd ?? Fs.cwd(),
3039
- stdio,
3040
- ...inherit.length > 0 ? { inherit } : {},
3041
- ...exec ? { exec } : {}
3042
- },
3043
- Infinity,
3044
- `proc-spawn ${file}`
3045
- );
3057
+ const req = {
3058
+ op: "proc-spawn",
3059
+ file,
3060
+ argv,
3061
+ env: env ?? deps.env,
3062
+ cwd: cwd ?? Fs.cwd(),
3063
+ stdio,
3064
+ ...inherit.length > 0 ? { inherit } : {},
3065
+ ...exec ? { exec } : {},
3066
+ restart: true
3067
+ };
3068
+ const r = restarted(() => transport.call(req, Infinity, `proc-spawn ${file}`));
3046
3069
  if (!r.ok) return -wasiErrno(r.errno);
3047
3070
  const pid = r.kind === "json" ? r.json : 0;
3048
3071
  const captures = [1, 2].filter((n) => "capture" in stdio[n]);
@@ -3064,14 +3087,10 @@ function createProcessKernel(deps) {
3064
3087
  return spawnChild(file, argv, env, cwd, fds, actions, false);
3065
3088
  },
3066
3089
  fork(state) {
3090
+ const snapshotAt = deps.deliveries?.();
3067
3091
  const unflushed = flushed(deps.beforeSpawn);
3068
3092
  if (unflushed < 0) return unflushed;
3069
- const streams = deps.describeFork();
3070
- const r = transport.call(
3071
- { op: "proc-fork", state: { ...state, streams, cwd: Fs.cwd() } },
3072
- Infinity,
3073
- "proc-fork"
3074
- );
3093
+ const r = forkRestarted(deps, state, snapshotAt);
3075
3094
  if (!r.ok) return -wasiErrno(r.errno);
3076
3095
  return r.kind === "json" ? r.json : -wasiErrno("EIO");
3077
3096
  },
@@ -3203,6 +3222,7 @@ var init_process_signals = __esm({
3203
3222
  reporting = false;
3204
3223
  unwinding = false;
3205
3224
  quieted = 0;
3225
+ delivered = 0;
3206
3226
  raw;
3207
3227
  header;
3208
3228
  hooks;
@@ -3226,6 +3246,9 @@ var init_process_signals = __esm({
3226
3246
  }
3227
3247
  };
3228
3248
  }
3249
+ deliveries() {
3250
+ return this.delivered;
3251
+ }
3229
3252
  restartable() {
3230
3253
  return this.lastDelivered !== 0 && (this.lastDelivered & ~this.restart) === 0;
3231
3254
  }
@@ -3267,6 +3290,7 @@ var init_process_signals = __esm({
3267
3290
  const timers = Atomics.exchange(this.header, SAB_I_TIMERS, 0);
3268
3291
  const pending = Atomics.exchange(this.header, SAB_I_SIGNALS, 0);
3269
3292
  if (this.depth <= 1) this.lastDelivered = pending | (timers & 1 ? sigbit(SIG.ALRM) : 0);
3293
+ if (pending !== 0 || timers !== 0) this.delivered++;
3270
3294
  for (let which = 0; which < 3; which++) {
3271
3295
  if (timers & 1 << which) this.hooks.timer?.(which);
3272
3296
  }
@@ -4033,12 +4057,12 @@ async function runWasmProcess(init, port3, deps = {}) {
4033
4057
  const say = (fd) => (text) => sys.write(fd, encoder4.encode(`${text}
4034
4058
  `));
4035
4059
  let ready;
4036
- let failed3;
4060
+ let failed4;
4037
4061
  let memory;
4038
4062
  let exports;
4039
4063
  const initialized = new Promise((resolve, reject) => {
4040
4064
  ready = resolve;
4041
- failed3 = reject;
4065
+ failed4 = reject;
4042
4066
  });
4043
4067
  const id = identify(transport, init);
4044
4068
  const module = {
@@ -4091,7 +4115,7 @@ async function runWasmProcess(init, port3, deps = {}) {
4091
4115
  exports = instance.exports;
4092
4116
  publishMemory(init.sab, memory?.buffer.byteLength ?? 0);
4093
4117
  done(instance, init.program.module);
4094
- }, failed3);
4118
+ }, failed4);
4095
4119
  return {};
4096
4120
  },
4097
4121
  preRun: [
@@ -4152,6 +4176,8 @@ async function runWasmProcess(init, port3, deps = {}) {
4152
4176
  pid: init.pid,
4153
4177
  raise: (sig) => running.sliccRaise?.(sig),
4154
4178
  restartable,
4179
+ memory: () => memory,
4180
+ deliveries: () => signals.deliveries(),
4155
4181
  describeFork: () => describeForFork(running.FS, sys, streams, livePath),
4156
4182
  inherit: (actions) => describeInherited(running.FS, sys, streams, livePath, actions),
4157
4183
  stdioPromoter: () => vfsPromoter(running.FS, sys, streams, livePath)
@@ -6063,108 +6089,435 @@ var init_wasi_host = __esm({
6063
6089
  }
6064
6090
  });
6065
6091
 
6066
- // src/process/wasi/wasi-imports.ts
6067
- function base64(text) {
6068
- const bytes = new TextEncoder().encode(text);
6069
- let binary = "";
6070
- for (let at = 0; at < bytes.length; at += 32768) {
6071
- binary += String.fromCharCode(...bytes.subarray(at, at + 32768));
6072
- }
6073
- return btoa(binary);
6092
+ // src/process/wasi/wasi-threads.ts
6093
+ function threadCap(env) {
6094
+ const asked = Number.parseInt(env.SLICC_WASM_THREADS ?? "", 10);
6095
+ return asked >= 1 ? Math.min(asked, WASM_MAX_THREADS) : WASM_DEFAULT_THREADS;
6074
6096
  }
6075
- function importSource(source) {
6076
- return import(`data:text/javascript;base64,${base64(source)}`);
6097
+ var LAST_TID, RUNNING, MAIN_TID, ThreadExit, WasiThreads;
6098
+ var init_wasi_threads = __esm({
6099
+ "src/process/wasi/wasi-threads.ts"() {
6100
+ "use strict";
6101
+ init_protocol();
6102
+ LAST_TID = 0;
6103
+ RUNNING = 1;
6104
+ MAIN_TID = 1;
6105
+ ThreadExit = class extends Error {
6106
+ constructor() {
6107
+ super("thread exit");
6108
+ }
6109
+ };
6110
+ WasiThreads = class {
6111
+ ids;
6112
+ beforeSpawn;
6113
+ modules;
6114
+ received;
6115
+ port;
6116
+ memory;
6117
+ cap;
6118
+ tid;
6119
+ constructor(port3, memory, cap, tid, ids) {
6120
+ this.port = port3;
6121
+ this.memory = memory;
6122
+ this.cap = cap;
6123
+ this.tid = tid;
6124
+ this.ids = new Int32Array(ids ?? new SharedArrayBuffer(16));
6125
+ if (!ids) Atomics.store(this.ids, LAST_TID, MAIN_TID);
6126
+ }
6127
+ spawn(arg) {
6128
+ if (Atomics.add(this.ids, RUNNING, 1) + 1 >= this.cap) {
6129
+ Atomics.sub(this.ids, RUNNING, 1);
6130
+ return -1;
6131
+ }
6132
+ this.beforeSpawn?.();
6133
+ const tid = Atomics.add(this.ids, LAST_TID, 1) + 1;
6134
+ const modules = this.modules?.();
6135
+ this.port.postMessage({
6136
+ type: WASM_THREAD_SPAWN,
6137
+ thread: {
6138
+ tid,
6139
+ arg,
6140
+ memory: this.memory,
6141
+ ids: this.ids.buffer,
6142
+ ...modules ? { modules } : {}
6143
+ }
6144
+ });
6145
+ return tid;
6146
+ }
6147
+ exited() {
6148
+ Atomics.sub(this.ids, RUNNING, 1);
6149
+ this.port.postMessage({ type: WASM_THREAD_EXIT });
6150
+ }
6151
+ known(tid) {
6152
+ return tid >= MAIN_TID && tid <= Atomics.load(this.ids, LAST_TID);
6153
+ }
6154
+ parallelism() {
6155
+ const cores = globalThis.navigator?.hardwareConcurrency;
6156
+ return Math.max(1, Math.min(this.cap, cores ?? this.cap));
6157
+ }
6158
+ };
6159
+ }
6160
+ });
6161
+
6162
+ // src/fs/physical-path.ts
6163
+ function start(path) {
6164
+ return { done: [], todo: path.split("/").filter((p) => p !== ""), hops: 0 };
6077
6165
  }
6078
- async function loadImports(source) {
6079
- const loaded = await importSource(source);
6080
- if (typeof loaded.createImports !== "function") {
6081
- throw new Error("the imports module exports no createImports function");
6166
+ function next(walk) {
6167
+ while (walk.todo.length > 0) {
6168
+ const part = walk.todo.shift();
6169
+ if (part === ".") continue;
6170
+ if (part === "..") {
6171
+ walk.done.pop();
6172
+ continue;
6173
+ }
6174
+ return part;
6082
6175
  }
6083
- return loaded.createImports;
6176
+ return void 0;
6084
6177
  }
6085
- function value(result) {
6086
- if (!result.ok) throw new WasiError(result.errno);
6087
- if (result.kind === "json") return result.json;
6088
- return result.kind === "bytes" ? result.bytes : void 0;
6178
+ function lexical(path) {
6179
+ const walk = start(path);
6180
+ for (let part = next(walk); part !== void 0; part = next(walk)) walk.done.push(part);
6181
+ return `/${walk.done.join("/")}`;
6089
6182
  }
6090
- function code(err) {
6091
- const c = err?.code;
6092
- return typeof c === "string" ? c : void 0;
6183
+ function rest(walk, part) {
6184
+ return lexical(`/${[...walk.done, part, ...walk.todo].join("/")}`);
6093
6185
  }
6094
- function importsContext({
6095
- host,
6096
- raw,
6097
- tid,
6098
- memory,
6099
- instance
6100
- }) {
6101
- const { fs } = host.o;
6102
- const call2 = (req) => value(raw(req));
6103
- const pathOf = (fd) => {
6104
- const e = host.fds.get(fd);
6105
- if (e.type === "file") return e.file.path;
6106
- if (e.type === "dir") return e.path;
6107
- if (e.type === "kernel" && host.fds.kind(fd, e) === "file") {
6108
- return call2({ op: "fd-vfs-stat", fd }).path;
6186
+ function follow(walk, target) {
6187
+ if (++walk.hops > MAX_HOPS) return false;
6188
+ if (target.startsWith("/")) walk.done.length = 0;
6189
+ walk.todo = [...target.split("/").filter((p) => p !== ""), ...walk.todo];
6190
+ return true;
6191
+ }
6192
+ function physicalPath(fs, path) {
6193
+ const walk = start(path);
6194
+ for (let part = next(walk); part !== void 0; part = next(walk)) {
6195
+ const at = `/${[...walk.done, part].join("/")}`;
6196
+ let target;
6197
+ try {
6198
+ target = fs.lstat(at).isSymbolicLink ? fs.readlink(at) : void 0;
6199
+ } catch {
6200
+ return rest(walk, part);
6109
6201
  }
6110
- return void 0;
6111
- };
6112
- const requirePath = (fd) => {
6113
- const path = pathOf(fd);
6114
- if (path === void 0) throw new WasiError("EBADF");
6115
- return path;
6116
- };
6117
- const fds = {
6118
- open(path, o = {}) {
6119
- const abs = host.fds.resolve(3, path);
6120
- if (o.nofollow && fs.exists(abs) && fs.lstat(abs).isSymbolicLink)
6121
- throw new WasiError("ELOOP");
6122
- const existed = fs.exists(abs);
6123
- const oflags = (o.create ? OFLAGS.CREAT : 0) | (o.exclusive ? OFLAGS.EXCL : 0) | (o.truncate ? OFLAGS.TRUNC : 0) | (o.directory ? OFLAGS.DIRECTORY : 0);
6124
- const rights = (o.write ? RIGHTS.FD_WRITE : 0n) | (o.read || !o.write ? RIGHTS.FD_READ : 0n);
6125
- const fd = host.fds.open(abs, oflags, rights, o.append ? FDFLAGS.APPEND : 0);
6126
- if (o.mode !== void 0 && !existed) fs.chmod(abs, o.mode);
6127
- return fd;
6128
- },
6129
- close(fd) {
6130
- host.fds.close(fd);
6131
- },
6132
- fstat(fd) {
6133
- const e = host.fds.get(fd);
6134
- const path = pathOf(fd);
6135
- if (path === void 0) {
6136
- const kind = e.type === "device" ? "device" : "stream";
6137
- return { kind, mode: kind === "device" ? 8630 : 4480, uid: UID2, gid: UID2, size: 0 };
6202
+ if (target === void 0) walk.done.push(part);
6203
+ else if (!follow(walk, target)) {
6204
+ throw Object.assign(new Error("too many levels of symbolic links"), { code: "ELOOP" });
6205
+ }
6206
+ }
6207
+ return `/${walk.done.join("/")}`;
6208
+ }
6209
+ var MAX_HOPS;
6210
+ var init_physical_path = __esm({
6211
+ "src/fs/physical-path.ts"() {
6212
+ "use strict";
6213
+ MAX_HOPS = 40;
6214
+ }
6215
+ });
6216
+
6217
+ // src/process/wasi/wasix-process.ts
6218
+ function restarted2(issue) {
6219
+ for (; ; ) {
6220
+ try {
6221
+ return issue();
6222
+ } catch (e) {
6223
+ if (e?.code !== "EINTR") throw e;
6224
+ }
6225
+ }
6226
+ }
6227
+ function resolveFrom(cwd, path) {
6228
+ return normalize(path.startsWith("/") ? path : `${cwd}/${path}`);
6229
+ }
6230
+ var O_WRONLY5, O_RDWR5, O_APPEND2, OFLAG_CREAT, OFLAG_TRUNC, WasixProcess;
6231
+ var init_wasix_process = __esm({
6232
+ "src/process/wasi/wasix-process.ts"() {
6233
+ "use strict";
6234
+ init_physical_path();
6235
+ init_wasi_files();
6236
+ init_wasi_host();
6237
+ O_WRONLY5 = 1;
6238
+ O_RDWR5 = 2;
6239
+ O_APPEND2 = 1024;
6240
+ OFLAG_CREAT = 1;
6241
+ OFLAG_TRUNC = 8;
6242
+ WasixProcess = class {
6243
+ host;
6244
+ driver;
6245
+ inThread;
6246
+ constructor(host, driver, inThread = () => false) {
6247
+ this.host = host;
6248
+ this.driver = driver;
6249
+ this.inThread = inThread;
6138
6250
  }
6139
- host.fds.flushPath(path);
6140
- const s = fs.stat(path);
6141
- return {
6142
- kind: s.isDirectory ? "dir" : "file",
6143
- path,
6144
- mode: s.mode ?? (s.isDirectory ? 16877 : 33188),
6145
- uid: UID2,
6146
- gid: UID2,
6147
- size: s.size,
6148
- ...s.ino !== void 0 ? { ino: s.ino } : {},
6149
- ...s.mtimeMs !== void 0 ? { mtimeMs: s.mtimeMs } : {}
6150
- };
6151
- },
6152
- fchmod(fd, mode) {
6153
- fs.chmod(requirePath(fd), mode);
6154
- },
6155
- tryLock(fd, exclusive) {
6156
- const path = requirePath(fd);
6157
- try {
6158
- call2({ op: "lock", path, exclusive, fd });
6159
- } catch (err) {
6160
- if (code(err) === "EAGAIN") return E.AGAIN;
6161
- throw err;
6251
+ restart() {
6252
+ return this.inThread() ? {} : { restart: true };
6162
6253
  }
6163
- return E.SUCCESS;
6164
- },
6165
- unlock(fd) {
6166
- call2({ op: "unlock", path: requirePath(fd) });
6167
- }
6254
+ call(req) {
6255
+ return this.host.o.kernel.call(req);
6256
+ }
6257
+ environment() {
6258
+ return { ...this.host.o.env, PWD: this.host.cwd };
6259
+ }
6260
+ locate(name, search, path) {
6261
+ if (name.includes("/"))
6262
+ return name.startsWith("/") ? name : normalize(`${this.host.cwd}/${name}`);
6263
+ if (!search) return name;
6264
+ for (const dir of path.split(":")) {
6265
+ if (!dir) continue;
6266
+ const candidate = normalize(
6267
+ `${dir.startsWith("/") ? "" : `${this.host.cwd}/`}${dir}/${name}`
6268
+ );
6269
+ if (this.host.o.fs.exists(candidate)) return candidate;
6270
+ }
6271
+ return name;
6272
+ }
6273
+ childFds(ops) {
6274
+ const { fds } = this.host;
6275
+ fds.promoteFiles();
6276
+ const map = fds.inheritable();
6277
+ const nulls = /* @__PURE__ */ new Set();
6278
+ const opened = [];
6279
+ let cwd = this.host.cwd;
6280
+ try {
6281
+ for (const op of ops) cwd = this.applyFdOp(op, { map, nulls, opened }, cwd);
6282
+ } catch (e) {
6283
+ for (const kfd of opened) this.host.o.kernel.sys.close(kfd);
6284
+ throw e;
6285
+ }
6286
+ const stdio = [0, 1, 2].map((fd) => {
6287
+ const k = map.get(fd);
6288
+ return k === void 0 ? { none: true } : { fd: k };
6289
+ });
6290
+ const inherit = [
6291
+ ...[...map].filter(([fd]) => fd > 2).map(([fd, kernel]) => ({ fd, kernel })),
6292
+ ...[...nulls].filter((fd) => fd > 2).map((fd) => ({ fd, device: "null" }))
6293
+ ];
6294
+ return { stdio, inherit, cwd, opened };
6295
+ }
6296
+ applyFdOp(op, slots2, cwd) {
6297
+ const { map, nulls, opened } = slots2;
6298
+ const { fds } = this.host;
6299
+ const point = (fd, kfd) => {
6300
+ if (kfd === void 0) {
6301
+ map.delete(fd);
6302
+ nulls.add(fd);
6303
+ } else {
6304
+ map.set(fd, kfd);
6305
+ nulls.delete(fd);
6306
+ }
6307
+ };
6308
+ if (op.cmd === "close") {
6309
+ map.delete(op.fd);
6310
+ nulls.delete(op.fd);
6311
+ } else if (op.cmd === "dup2" && nulls.has(op.srcFd)) point(op.fd, void 0);
6312
+ else if (op.cmd === "dup2") {
6313
+ const src = map.get(op.srcFd) ?? (fds.find(op.srcFd)?.type === "kernel" ? op.srcFd : void 0);
6314
+ if (src === void 0) throw Object.assign(new Error("EBADF"), { code: "EBADF" });
6315
+ point(op.fd, src);
6316
+ } else if (op.cmd === "open" && resolveFrom(cwd, op.path) === "/dev/null") {
6317
+ point(op.fd, void 0);
6318
+ } else if (op.cmd === "open") {
6319
+ const kfd = this.openFor(op, cwd);
6320
+ opened.push(kfd);
6321
+ point(op.fd, kfd);
6322
+ } else if (op.cmd === "chdir") return this.physicalFrom(cwd, op.path);
6323
+ else return physicalPath(this.host.o.fs, fds.dir(op.fd).path);
6324
+ return cwd;
6325
+ }
6326
+ physicalFrom(cwd, path) {
6327
+ return physicalPath(this.host.o.fs, path.startsWith("/") ? path : `${cwd}/${path}`);
6328
+ }
6329
+ openFor(op, cwd) {
6330
+ const path = resolveFrom(cwd, op.path);
6331
+ const create = (op.oflags & OFLAG_CREAT) !== 0;
6332
+ if (!create && !this.host.o.fs.exists(path)) {
6333
+ throw Object.assign(new Error("ENOENT"), { code: "ENOENT" });
6334
+ }
6335
+ const flags = (op.rightsWrite ? O_RDWR5 : 0) | (op.append ? O_APPEND2 : 0);
6336
+ return this.host.o.kernel.sys.openVfs(path, op.rightsWrite ? flags || O_WRONLY5 : 0, 0, {
6337
+ ...create ? { create } : {},
6338
+ ...op.oflags & OFLAG_TRUNC ? { truncate: true } : {}
6339
+ });
6340
+ }
6341
+ spawn(req, exec = false) {
6342
+ const { stdio, inherit, cwd, opened } = this.childFds(req.ops ?? []);
6343
+ try {
6344
+ const spawn = {
6345
+ op: "proc-spawn",
6346
+ file: this.locate(req.name, req.search, req.path),
6347
+ argv: req.argv.length > 0 ? req.argv : [req.name],
6348
+ env: req.env ?? this.environment(),
6349
+ cwd,
6350
+ stdio,
6351
+ inherit,
6352
+ ...exec ? { exec } : {},
6353
+ ...this.restart()
6354
+ };
6355
+ return restarted2(() => this.call(spawn));
6356
+ } finally {
6357
+ for (const kfd of opened) this.host.o.kernel.sys.close(kfd);
6358
+ this.host.o.fs.invalidate?.();
6359
+ }
6360
+ }
6361
+ exec(req) {
6362
+ const pid = this.spawn(req, true);
6363
+ const [, status2] = this.call({ op: "proc-exec", pid });
6364
+ const sig = status2 & 127;
6365
+ throw new WasiExit(sig ? 128 + sig : status2 >> 8 & 255);
6366
+ }
6367
+ join(pidPtr, flags, statusPtr) {
6368
+ const v = this.host.mem.view();
6369
+ const pid = v.getUint8(pidPtr) === 1 ? v.getUint32(pidPtr + 4, true) : -1;
6370
+ this.host.mem.bytes(statusPtr, 6).fill(0);
6371
+ const [child, status2] = this.call({ op: "proc-wait", pid, nohang: (flags & 1) !== 0 });
6372
+ if (child === 0) return;
6373
+ this.host.o.fs.invalidate?.();
6374
+ v.setUint8(pidPtr, 1);
6375
+ v.setUint32(pidPtr + 4, child, true);
6376
+ const sig = status2 & 127;
6377
+ if (sig) {
6378
+ v.setUint8(statusPtr, 2);
6379
+ v.setUint8(statusPtr + 4, sig);
6380
+ } else {
6381
+ v.setUint8(statusPtr, 1);
6382
+ v.setUint16(statusPtr + 2, status2 >> 8 & 255, true);
6383
+ }
6384
+ }
6385
+ fork(pidPtr) {
6386
+ const back = this.driver.rewound();
6387
+ if (back !== void 0) {
6388
+ this.host.mem.view().setUint32(pidPtr, back, true);
6389
+ return void 0;
6390
+ }
6391
+ return this.driver.fork(
6392
+ (asyncifyData, globals, forkSp) => restarted2(() => this.forkCall(asyncifyData, globals, forkSp))
6393
+ );
6394
+ }
6395
+ forkCall(asyncifyData, globals, forkSp) {
6396
+ const { fds } = this.host;
6397
+ fds.promoteFiles();
6398
+ const memory = this.host.mem.bytes(0, this.host.mem.size()).slice();
6399
+ const wasi = {
6400
+ asyncifyData,
6401
+ globals,
6402
+ fds: fds.snapshot(),
6403
+ cloexec: [...fds.cloexec],
6404
+ cwd: this.host.cwd,
6405
+ ...fds.isShared ? { shared: true } : {},
6406
+ setjmps: this.driver.setjmps(),
6407
+ ...this.host.signals ? { signals: this.host.signals.snapshot() } : {}
6408
+ };
6409
+ return this.call({
6410
+ op: "proc-fork",
6411
+ state: { memory, currData: 0, forkSp, callStackNames: [], ppid: this.host.o.pid, wasi },
6412
+ ...this.restart()
6413
+ });
6414
+ }
6415
+ };
6416
+ }
6417
+ });
6418
+
6419
+ // src/process/wasi/wasi-imports.ts
6420
+ function base64(text) {
6421
+ const bytes = new TextEncoder().encode(text);
6422
+ let binary = "";
6423
+ for (let at = 0; at < bytes.length; at += 32768) {
6424
+ binary += String.fromCharCode(...bytes.subarray(at, at + 32768));
6425
+ }
6426
+ return btoa(binary);
6427
+ }
6428
+ function importSource(source) {
6429
+ return import(`data:text/javascript;base64,${base64(source)}`);
6430
+ }
6431
+ async function loadImports(source) {
6432
+ const loaded = await importSource(source);
6433
+ if (typeof loaded.createImports !== "function") {
6434
+ throw new Error("the imports module exports no createImports function");
6435
+ }
6436
+ return loaded.createImports;
6437
+ }
6438
+ function value(result) {
6439
+ if (!result.ok) throw new WasiError(result.errno);
6440
+ if (result.kind === "json") return result.json;
6441
+ return result.kind === "bytes" ? result.bytes : void 0;
6442
+ }
6443
+ function code(err) {
6444
+ const c = err?.code;
6445
+ return typeof c === "string" ? c : void 0;
6446
+ }
6447
+ function importsContext({
6448
+ host,
6449
+ raw,
6450
+ tid,
6451
+ memory,
6452
+ instance
6453
+ }) {
6454
+ const { fs } = host.o;
6455
+ const call2 = (req) => value(raw(req));
6456
+ const pathOf = (fd) => {
6457
+ const e = host.fds.get(fd);
6458
+ if (e.type === "file") return e.file.path;
6459
+ if (e.type === "dir") return e.path;
6460
+ if (e.type === "kernel" && host.fds.kind(fd, e) === "file") {
6461
+ return call2({ op: "fd-vfs-stat", fd }).path;
6462
+ }
6463
+ return void 0;
6464
+ };
6465
+ const requirePath = (fd) => {
6466
+ const path = pathOf(fd);
6467
+ if (path === void 0) throw new WasiError("EBADF");
6468
+ return path;
6469
+ };
6470
+ const fds = {
6471
+ open(path, o = {}) {
6472
+ const abs = host.fds.resolve(3, path);
6473
+ if (o.nofollow && fs.exists(abs) && fs.lstat(abs).isSymbolicLink)
6474
+ throw new WasiError("ELOOP");
6475
+ const existed = fs.exists(abs);
6476
+ const oflags = (o.create ? OFLAGS.CREAT : 0) | (o.exclusive ? OFLAGS.EXCL : 0) | (o.truncate ? OFLAGS.TRUNC : 0) | (o.directory ? OFLAGS.DIRECTORY : 0);
6477
+ const rights = (o.write ? RIGHTS.FD_WRITE : 0n) | (o.read || !o.write ? RIGHTS.FD_READ : 0n);
6478
+ const fd = host.fds.open(abs, oflags, rights, o.append ? FDFLAGS.APPEND : 0);
6479
+ if (o.mode !== void 0 && !existed) fs.chmod(abs, o.mode);
6480
+ return fd;
6481
+ },
6482
+ close(fd) {
6483
+ host.fds.close(fd);
6484
+ },
6485
+ fstat(fd) {
6486
+ const e = host.fds.get(fd);
6487
+ const path = pathOf(fd);
6488
+ if (path === void 0) {
6489
+ const kind = e.type === "device" ? "device" : "stream";
6490
+ return { kind, mode: kind === "device" ? 8630 : 4480, uid: UID2, gid: UID2, size: 0 };
6491
+ }
6492
+ host.fds.flushPath(path);
6493
+ const s = fs.stat(path);
6494
+ return {
6495
+ kind: s.isDirectory ? "dir" : "file",
6496
+ path,
6497
+ mode: s.mode ?? (s.isDirectory ? 16877 : 33188),
6498
+ uid: UID2,
6499
+ gid: UID2,
6500
+ size: s.size,
6501
+ ...s.ino !== void 0 ? { ino: s.ino } : {},
6502
+ ...s.mtimeMs !== void 0 ? { mtimeMs: s.mtimeMs } : {}
6503
+ };
6504
+ },
6505
+ fchmod(fd, mode) {
6506
+ fs.chmod(requirePath(fd), mode);
6507
+ },
6508
+ tryLock(fd, exclusive) {
6509
+ const path = requirePath(fd);
6510
+ try {
6511
+ call2({ op: "lock", path, exclusive, fd });
6512
+ } catch (err) {
6513
+ if (code(err) === "EAGAIN") return E.AGAIN;
6514
+ throw err;
6515
+ }
6516
+ return E.SUCCESS;
6517
+ },
6518
+ unlock(fd) {
6519
+ call2({ op: "unlock", path: requirePath(fd) });
6520
+ }
6168
6521
  };
6169
6522
  return {
6170
6523
  memory,
@@ -6176,7 +6529,7 @@ function importsContext({
6176
6529
  fs,
6177
6530
  fds,
6178
6531
  syscall: call2,
6179
- ...processes(host, call2),
6532
+ ...processes(host, call2, tid !== MAIN_TID),
6180
6533
  async: {
6181
6534
  submit: (req) => call2({ op: "async-submit", req }),
6182
6535
  wait(timeoutMs) {
@@ -6206,7 +6559,7 @@ function importsContext({
6206
6559
  errno: (err) => wasiErrnoOf(code(err))
6207
6560
  };
6208
6561
  }
6209
- function processes(host, call2) {
6562
+ function processes(host, call2, inThread) {
6210
6563
  const close = (fd) => void call2({ op: "fd-close", fd });
6211
6564
  const slot = (n, how, mine, theirs) => {
6212
6565
  if (how === "inherit") return { fd: n };
@@ -6223,14 +6576,16 @@ function processes(host, call2) {
6223
6576
  host.fds.promoteFiles();
6224
6577
  try {
6225
6578
  const stdio = STDIO.map((name, n) => slot(n, o[name] ?? "inherit", mine, theirs));
6226
- const pid = call2({
6579
+ const req = {
6227
6580
  op: "proc-spawn",
6228
6581
  file: o.argv[0],
6229
6582
  argv: o.argv,
6230
6583
  env: o.env ?? { ...host.o.env },
6231
6584
  cwd: o.cwd ?? host.cwd,
6232
- stdio
6233
- });
6585
+ stdio,
6586
+ ...inThread ? {} : { restart: true }
6587
+ };
6588
+ const pid = restarted2(() => call2(req));
6234
6589
  const out = { pid };
6235
6590
  STDIO.forEach((name, n) => {
6236
6591
  if (mine[n] !== void 0) out[name] = mine[n];
@@ -6267,6 +6622,8 @@ var init_wasi_imports = __esm({
6267
6622
  "use strict";
6268
6623
  init_wasi_abi();
6269
6624
  init_wasi_files();
6625
+ init_wasi_threads();
6626
+ init_wasix_process();
6270
6627
  UID2 = 1e3;
6271
6628
  STDIO = ["stdin", "stdout", "stderr"];
6272
6629
  }
@@ -6467,76 +6824,6 @@ var init_wasi_stats = __esm({
6467
6824
  }
6468
6825
  });
6469
6826
 
6470
- // src/process/wasi/wasi-threads.ts
6471
- function threadCap(env) {
6472
- const asked = Number.parseInt(env.SLICC_WASM_THREADS ?? "", 10);
6473
- return asked >= 1 ? Math.min(asked, WASM_MAX_THREADS) : WASM_DEFAULT_THREADS;
6474
- }
6475
- var LAST_TID, RUNNING, MAIN_TID, ThreadExit, WasiThreads;
6476
- var init_wasi_threads = __esm({
6477
- "src/process/wasi/wasi-threads.ts"() {
6478
- "use strict";
6479
- init_protocol();
6480
- LAST_TID = 0;
6481
- RUNNING = 1;
6482
- MAIN_TID = 1;
6483
- ThreadExit = class extends Error {
6484
- constructor() {
6485
- super("thread exit");
6486
- }
6487
- };
6488
- WasiThreads = class {
6489
- ids;
6490
- beforeSpawn;
6491
- modules;
6492
- received;
6493
- port;
6494
- memory;
6495
- cap;
6496
- tid;
6497
- constructor(port3, memory, cap, tid, ids) {
6498
- this.port = port3;
6499
- this.memory = memory;
6500
- this.cap = cap;
6501
- this.tid = tid;
6502
- this.ids = new Int32Array(ids ?? new SharedArrayBuffer(16));
6503
- if (!ids) Atomics.store(this.ids, LAST_TID, MAIN_TID);
6504
- }
6505
- spawn(arg) {
6506
- if (Atomics.add(this.ids, RUNNING, 1) + 1 >= this.cap) {
6507
- Atomics.sub(this.ids, RUNNING, 1);
6508
- return -1;
6509
- }
6510
- this.beforeSpawn?.();
6511
- const tid = Atomics.add(this.ids, LAST_TID, 1) + 1;
6512
- const modules = this.modules?.();
6513
- this.port.postMessage({
6514
- type: WASM_THREAD_SPAWN,
6515
- thread: {
6516
- tid,
6517
- arg,
6518
- memory: this.memory,
6519
- ids: this.ids.buffer,
6520
- ...modules ? { modules } : {}
6521
- }
6522
- });
6523
- return tid;
6524
- }
6525
- exited() {
6526
- Atomics.sub(this.ids, RUNNING, 1);
6527
- this.port.postMessage({ type: WASM_THREAD_EXIT });
6528
- }
6529
- known(tid) {
6530
- return tid >= MAIN_TID && tid <= Atomics.load(this.ids, LAST_TID);
6531
- }
6532
- parallelism() {
6533
- const cores = globalThis.navigator?.hardwareConcurrency;
6534
- return Math.max(1, Math.min(this.cap, cores ?? this.cap));
6535
- }
6536
- };
6537
- }
6538
- });
6539
-
6540
6827
  // src/process/wasi/wasix-fork.ts
6541
6828
  function mutableGlobals(exports) {
6542
6829
  const out = [];
@@ -6898,325 +7185,88 @@ var init_wasix_linker = __esm({
6898
7185
  pending.push(() => {
6899
7186
  g.value = this.slotOrNull(imp.name);
6900
7187
  });
6901
- }
6902
- }
6903
- const imports = {
6904
- ...this.host.hostImports(module),
6905
- env,
6906
- "GOT.mem": gotMem,
6907
- "GOT.func": gotFunc
6908
- };
6909
- linked.instance = new WebAssembly.Instance(module, imports);
6910
- this.modules.set(at.handle, linked);
6911
- this.byPath.set(path, linked);
6912
- for (const resolve of pending) resolve();
6913
- if (init) {
6914
- call(linked.instance, "__wasm_apply_data_relocs");
6915
- call(linked.instance, "__wasm_call_ctors");
6916
- } else {
6917
- call(linked.instance, "__wasix_init_tls");
6918
- }
6919
- return linked;
6920
- }
6921
- functionImport(name) {
6922
- const now = this.find(name);
6923
- if (now && typeof now[1] === "function") return now[1];
6924
- let resolved2;
6925
- return (...args) => {
6926
- if (!resolved2) {
6927
- const later = this.find(name);
6928
- if (!later || typeof later[1] !== "function")
6929
- throw new WebAssembly.RuntimeError(`unresolved symbol ${name}`);
6930
- resolved2 = later[1];
6931
- }
6932
- return resolved2(...args);
6933
- };
6934
- }
6935
- addressOrNull(name) {
6936
- const found = this.find(name);
6937
- if (!found || !(found[1] instanceof WebAssembly.Global)) return 0;
6938
- return this.baseOf(found[0]) + found[1].value;
6939
- }
6940
- slotOrNull(name) {
6941
- const found = this.find(name);
6942
- if (!found || typeof found[1] !== "function") return 0;
6943
- return this.slot(found[1], found[0], name);
6944
- }
6945
- find(name) {
6946
- const inMain = this.main?.exports[name];
6947
- if (inMain !== void 0) return [0, inMain];
6948
- for (const m of this.modules.values()) {
6949
- const v = m.instance?.exports[name];
6950
- if (v !== void 0) return [m.handle, v];
6951
- }
6952
- return void 0;
6953
- }
6954
- findIn(m, name, seen) {
6955
- if (seen.has(m.handle)) return void 0;
6956
- seen.add(m.handle);
6957
- const v = m.instance.exports[name];
6958
- if (v !== void 0) return [m.handle, v];
6959
- for (const h of m.needed) {
6960
- const found = this.findIn(this.module(h), name, seen);
6961
- if (found) return found;
6962
- }
6963
- return void 0;
6964
- }
6965
- baseOf(handle) {
6966
- return handle === 0 ? this.memoryBase : this.module(handle).memoryBase;
6967
- }
6968
- slot(fn, handle, name) {
6969
- const known = this.slots.get(fn);
6970
- if (known !== void 0) return known;
6971
- const index2 = this.table.length;
6972
- this.table.grow(1);
6973
- this.table.set(index2, fn);
6974
- this.slots.set(fn, index2);
6975
- this.publisher?.({ kind: "slot", index: index2, handle, name });
6976
- return index2;
6977
- }
6978
- allocate(size, alignment) {
6979
- if (size === 0) return 0;
6980
- const base = align(this.memory.buffer.byteLength, Math.max(alignment, 16));
6981
- growTo(this.memory, base + size);
6982
- return base;
6983
- }
6984
- };
6985
- }
6986
- });
6987
-
6988
- // src/fs/physical-path.ts
6989
- function start(path) {
6990
- return { done: [], todo: path.split("/").filter((p) => p !== ""), hops: 0 };
6991
- }
6992
- function next(walk) {
6993
- while (walk.todo.length > 0) {
6994
- const part = walk.todo.shift();
6995
- if (part === ".") continue;
6996
- if (part === "..") {
6997
- walk.done.pop();
6998
- continue;
6999
- }
7000
- return part;
7001
- }
7002
- return void 0;
7003
- }
7004
- function lexical(path) {
7005
- const walk = start(path);
7006
- for (let part = next(walk); part !== void 0; part = next(walk)) walk.done.push(part);
7007
- return `/${walk.done.join("/")}`;
7008
- }
7009
- function rest(walk, part) {
7010
- return lexical(`/${[...walk.done, part, ...walk.todo].join("/")}`);
7011
- }
7012
- function follow(walk, target) {
7013
- if (++walk.hops > MAX_HOPS) return false;
7014
- if (target.startsWith("/")) walk.done.length = 0;
7015
- walk.todo = [...target.split("/").filter((p) => p !== ""), ...walk.todo];
7016
- return true;
7017
- }
7018
- function physicalPath(fs, path) {
7019
- const walk = start(path);
7020
- for (let part = next(walk); part !== void 0; part = next(walk)) {
7021
- const at = `/${[...walk.done, part].join("/")}`;
7022
- let target;
7023
- try {
7024
- target = fs.lstat(at).isSymbolicLink ? fs.readlink(at) : void 0;
7025
- } catch {
7026
- return rest(walk, part);
7027
- }
7028
- if (target === void 0) walk.done.push(part);
7029
- else if (!follow(walk, target)) {
7030
- throw Object.assign(new Error("too many levels of symbolic links"), { code: "ELOOP" });
7031
- }
7032
- }
7033
- return `/${walk.done.join("/")}`;
7034
- }
7035
- var MAX_HOPS;
7036
- var init_physical_path = __esm({
7037
- "src/fs/physical-path.ts"() {
7038
- "use strict";
7039
- MAX_HOPS = 40;
7040
- }
7041
- });
7042
-
7043
- // src/process/wasi/wasix-process.ts
7044
- function resolveFrom(cwd, path) {
7045
- return normalize(path.startsWith("/") ? path : `${cwd}/${path}`);
7046
- }
7047
- var O_WRONLY5, O_RDWR5, O_APPEND2, OFLAG_CREAT, OFLAG_TRUNC, WasixProcess;
7048
- var init_wasix_process = __esm({
7049
- "src/process/wasi/wasix-process.ts"() {
7050
- "use strict";
7051
- init_physical_path();
7052
- init_wasi_files();
7053
- init_wasi_host();
7054
- O_WRONLY5 = 1;
7055
- O_RDWR5 = 2;
7056
- O_APPEND2 = 1024;
7057
- OFLAG_CREAT = 1;
7058
- OFLAG_TRUNC = 8;
7059
- WasixProcess = class {
7060
- host;
7061
- driver;
7062
- constructor(host, driver) {
7063
- this.host = host;
7064
- this.driver = driver;
7065
- }
7066
- call(req) {
7067
- return this.host.o.kernel.call(req);
7068
- }
7069
- environment() {
7070
- return { ...this.host.o.env, PWD: this.host.cwd };
7071
- }
7072
- locate(name, search, path) {
7073
- if (name.includes("/"))
7074
- return name.startsWith("/") ? name : normalize(`${this.host.cwd}/${name}`);
7075
- if (!search) return name;
7076
- for (const dir of path.split(":")) {
7077
- if (!dir) continue;
7078
- const candidate = normalize(
7079
- `${dir.startsWith("/") ? "" : `${this.host.cwd}/`}${dir}/${name}`
7080
- );
7081
- if (this.host.o.fs.exists(candidate)) return candidate;
7188
+ }
7082
7189
  }
7083
- return name;
7084
- }
7085
- childFds(ops) {
7086
- const { fds } = this.host;
7087
- fds.promoteFiles();
7088
- const map = fds.inheritable();
7089
- const nulls = /* @__PURE__ */ new Set();
7090
- const opened = [];
7091
- let cwd = this.host.cwd;
7092
- try {
7093
- for (const op of ops) cwd = this.applyFdOp(op, { map, nulls, opened }, cwd);
7094
- } catch (e) {
7095
- for (const kfd of opened) this.host.o.kernel.sys.close(kfd);
7096
- throw e;
7190
+ const imports = {
7191
+ ...this.host.hostImports(module),
7192
+ env,
7193
+ "GOT.mem": gotMem,
7194
+ "GOT.func": gotFunc
7195
+ };
7196
+ linked.instance = new WebAssembly.Instance(module, imports);
7197
+ this.modules.set(at.handle, linked);
7198
+ this.byPath.set(path, linked);
7199
+ for (const resolve of pending) resolve();
7200
+ if (init) {
7201
+ call(linked.instance, "__wasm_apply_data_relocs");
7202
+ call(linked.instance, "__wasm_call_ctors");
7203
+ } else {
7204
+ call(linked.instance, "__wasix_init_tls");
7097
7205
  }
7098
- const stdio = [0, 1, 2].map((fd) => {
7099
- const k = map.get(fd);
7100
- return k === void 0 ? { none: true } : { fd: k };
7101
- });
7102
- const inherit = [
7103
- ...[...map].filter(([fd]) => fd > 2).map(([fd, kernel]) => ({ fd, kernel })),
7104
- ...[...nulls].filter((fd) => fd > 2).map((fd) => ({ fd, device: "null" }))
7105
- ];
7106
- return { stdio, inherit, cwd, opened };
7206
+ return linked;
7107
7207
  }
7108
- applyFdOp(op, slots2, cwd) {
7109
- const { map, nulls, opened } = slots2;
7110
- const { fds } = this.host;
7111
- const point = (fd, kfd) => {
7112
- if (kfd === void 0) {
7113
- map.delete(fd);
7114
- nulls.add(fd);
7115
- } else {
7116
- map.set(fd, kfd);
7117
- nulls.delete(fd);
7208
+ functionImport(name) {
7209
+ const now = this.find(name);
7210
+ if (now && typeof now[1] === "function") return now[1];
7211
+ let resolved2;
7212
+ return (...args) => {
7213
+ if (!resolved2) {
7214
+ const later = this.find(name);
7215
+ if (!later || typeof later[1] !== "function")
7216
+ throw new WebAssembly.RuntimeError(`unresolved symbol ${name}`);
7217
+ resolved2 = later[1];
7118
7218
  }
7219
+ return resolved2(...args);
7119
7220
  };
7120
- if (op.cmd === "close") {
7121
- map.delete(op.fd);
7122
- nulls.delete(op.fd);
7123
- } else if (op.cmd === "dup2" && nulls.has(op.srcFd)) point(op.fd, void 0);
7124
- else if (op.cmd === "dup2") {
7125
- const src = map.get(op.srcFd) ?? (fds.find(op.srcFd)?.type === "kernel" ? op.srcFd : void 0);
7126
- if (src === void 0) throw Object.assign(new Error("EBADF"), { code: "EBADF" });
7127
- point(op.fd, src);
7128
- } else if (op.cmd === "open" && resolveFrom(cwd, op.path) === "/dev/null") {
7129
- point(op.fd, void 0);
7130
- } else if (op.cmd === "open") {
7131
- const kfd = this.openFor(op, cwd);
7132
- opened.push(kfd);
7133
- point(op.fd, kfd);
7134
- } else if (op.cmd === "chdir") return this.physicalFrom(cwd, op.path);
7135
- else return physicalPath(this.host.o.fs, fds.dir(op.fd).path);
7136
- return cwd;
7137
7221
  }
7138
- physicalFrom(cwd, path) {
7139
- return physicalPath(this.host.o.fs, path.startsWith("/") ? path : `${cwd}/${path}`);
7222
+ addressOrNull(name) {
7223
+ const found = this.find(name);
7224
+ if (!found || !(found[1] instanceof WebAssembly.Global)) return 0;
7225
+ return this.baseOf(found[0]) + found[1].value;
7140
7226
  }
7141
- openFor(op, cwd) {
7142
- const path = resolveFrom(cwd, op.path);
7143
- const create = (op.oflags & OFLAG_CREAT) !== 0;
7144
- if (!create && !this.host.o.fs.exists(path)) {
7145
- throw Object.assign(new Error("ENOENT"), { code: "ENOENT" });
7227
+ slotOrNull(name) {
7228
+ const found = this.find(name);
7229
+ if (!found || typeof found[1] !== "function") return 0;
7230
+ return this.slot(found[1], found[0], name);
7231
+ }
7232
+ find(name) {
7233
+ const inMain = this.main?.exports[name];
7234
+ if (inMain !== void 0) return [0, inMain];
7235
+ for (const m of this.modules.values()) {
7236
+ const v = m.instance?.exports[name];
7237
+ if (v !== void 0) return [m.handle, v];
7146
7238
  }
7147
- const flags = (op.rightsWrite ? O_RDWR5 : 0) | (op.append ? O_APPEND2 : 0);
7148
- return this.host.o.kernel.sys.openVfs(path, op.rightsWrite ? flags || O_WRONLY5 : 0, 0, {
7149
- ...create ? { create } : {},
7150
- ...op.oflags & OFLAG_TRUNC ? { truncate: true } : {}
7151
- });
7239
+ return void 0;
7152
7240
  }
7153
- spawn(req, exec = false) {
7154
- const { stdio, inherit, cwd, opened } = this.childFds(req.ops ?? []);
7155
- try {
7156
- return this.call({
7157
- op: "proc-spawn",
7158
- file: this.locate(req.name, req.search, req.path),
7159
- argv: req.argv.length > 0 ? req.argv : [req.name],
7160
- env: req.env ?? this.environment(),
7161
- cwd,
7162
- stdio,
7163
- inherit,
7164
- ...exec ? { exec } : {}
7165
- });
7166
- } finally {
7167
- for (const kfd of opened) this.host.o.kernel.sys.close(kfd);
7168
- this.host.o.fs.invalidate?.();
7241
+ findIn(m, name, seen) {
7242
+ if (seen.has(m.handle)) return void 0;
7243
+ seen.add(m.handle);
7244
+ const v = m.instance.exports[name];
7245
+ if (v !== void 0) return [m.handle, v];
7246
+ for (const h of m.needed) {
7247
+ const found = this.findIn(this.module(h), name, seen);
7248
+ if (found) return found;
7169
7249
  }
7250
+ return void 0;
7170
7251
  }
7171
- exec(req) {
7172
- const pid = this.spawn(req, true);
7173
- const [, status2] = this.call({ op: "proc-exec", pid });
7174
- const sig = status2 & 127;
7175
- throw new WasiExit(sig ? 128 + sig : status2 >> 8 & 255);
7252
+ baseOf(handle) {
7253
+ return handle === 0 ? this.memoryBase : this.module(handle).memoryBase;
7176
7254
  }
7177
- join(pidPtr, flags, statusPtr) {
7178
- const v = this.host.mem.view();
7179
- const pid = v.getUint8(pidPtr) === 1 ? v.getUint32(pidPtr + 4, true) : -1;
7180
- this.host.mem.bytes(statusPtr, 6).fill(0);
7181
- const [child, status2] = this.call({ op: "proc-wait", pid, nohang: (flags & 1) !== 0 });
7182
- if (child === 0) return;
7183
- this.host.o.fs.invalidate?.();
7184
- v.setUint8(pidPtr, 1);
7185
- v.setUint32(pidPtr + 4, child, true);
7186
- const sig = status2 & 127;
7187
- if (sig) {
7188
- v.setUint8(statusPtr, 2);
7189
- v.setUint8(statusPtr + 4, sig);
7190
- } else {
7191
- v.setUint8(statusPtr, 1);
7192
- v.setUint16(statusPtr + 2, status2 >> 8 & 255, true);
7193
- }
7255
+ slot(fn, handle, name) {
7256
+ const known = this.slots.get(fn);
7257
+ if (known !== void 0) return known;
7258
+ const index2 = this.table.length;
7259
+ this.table.grow(1);
7260
+ this.table.set(index2, fn);
7261
+ this.slots.set(fn, index2);
7262
+ this.publisher?.({ kind: "slot", index: index2, handle, name });
7263
+ return index2;
7194
7264
  }
7195
- fork(pidPtr) {
7196
- const back = this.driver.rewound();
7197
- if (back !== void 0) {
7198
- this.host.mem.view().setUint32(pidPtr, back, true);
7199
- return void 0;
7200
- }
7201
- return this.driver.fork((asyncifyData, globals, forkSp) => {
7202
- const { fds } = this.host;
7203
- fds.promoteFiles();
7204
- const memory = this.host.mem.bytes(0, this.host.mem.size()).slice();
7205
- const wasi = {
7206
- asyncifyData,
7207
- globals,
7208
- fds: fds.snapshot(),
7209
- cloexec: [...fds.cloexec],
7210
- cwd: this.host.cwd,
7211
- ...fds.isShared ? { shared: true } : {},
7212
- setjmps: this.driver.setjmps(),
7213
- ...this.host.signals ? { signals: this.host.signals.snapshot() } : {}
7214
- };
7215
- return this.call({
7216
- op: "proc-fork",
7217
- state: { memory, currData: 0, forkSp, callStackNames: [], ppid: this.host.o.pid, wasi }
7218
- });
7219
- });
7265
+ allocate(size, alignment) {
7266
+ if (size === 0) return 0;
7267
+ const base = align(this.memory.buffer.byteLength, Math.max(alignment, 16));
7268
+ growTo(this.memory, base + size);
7269
+ return base;
7220
7270
  }
7221
7271
  };
7222
7272
  }
@@ -7530,7 +7580,11 @@ var init_wasix_host = __esm({
7530
7580
  constructor(host, driver, module) {
7531
7581
  this.host = host;
7532
7582
  this.driver = driver;
7533
- this.process = new WasixProcess(host, driver);
7583
+ this.process = new WasixProcess(
7584
+ host,
7585
+ driver,
7586
+ () => (this.threads?.tid ?? MAIN_TID) !== MAIN_TID
7587
+ );
7534
7588
  if (module && !WebAssembly.Module.imports(module).some((i) => i.name === "fd_fdflags_set")) {
7535
7589
  host.fds.implicitCloexec = true;
7536
7590
  host.interruptWakes = true;
@@ -7748,7 +7802,7 @@ var init_wasix_host = __esm({
7748
7802
  }
7749
7803
  dlImports() {
7750
7804
  const { mem, host } = this;
7751
- const failed3 = (message2, buf, len) => {
7805
+ const failed4 = (message2, buf, len) => {
7752
7806
  if (len > 0) {
7753
7807
  const bytes = new TextEncoder().encode(message2).subarray(0, len - 1);
7754
7808
  mem.bytes(buf, bytes.length).set(bytes);
@@ -7757,12 +7811,12 @@ var init_wasix_host = __esm({
7757
7811
  return E.NOEXEC;
7758
7812
  };
7759
7813
  const linked = (buf, len, op, out) => {
7760
- if (!this.linker) return failed3("not a dynamically-linked program", buf, len);
7814
+ if (!this.linker) return failed4("not a dynamically-linked program", buf, len);
7761
7815
  try {
7762
7816
  out(op(this.linker));
7763
7817
  return E.SUCCESS;
7764
7818
  } catch (e) {
7765
- if (e instanceof DlError) return failed3(e.message, buf, len);
7819
+ if (e instanceof DlError) return failed4(e.message, buf, len);
7766
7820
  throw e;
7767
7821
  }
7768
7822
  };
@@ -8761,6 +8815,239 @@ var init_js_children = __esm({
8761
8815
  }
8762
8816
  });
8763
8817
 
8818
+ // src/process/js/js-fetch.ts
8819
+ function withoutFragment(url) {
8820
+ url.hash = "";
8821
+ return url.href;
8822
+ }
8823
+ function failed2(err) {
8824
+ return new TypeError("fetch failed", { cause: err });
8825
+ }
8826
+ function plain(status2, text) {
8827
+ return new Response(text, {
8828
+ status: status2,
8829
+ headers: { "content-type": "text/plain; charset=utf-8" }
8830
+ });
8831
+ }
8832
+ function rewrite(hop, status2, location) {
8833
+ const next2 = new URL(location, hop.url);
8834
+ if (next2.protocol !== "http:" && next2.protocol !== "https:") {
8835
+ throw failed2(new JsCallError("EPROTONOSUPPORT", next2.protocol));
8836
+ }
8837
+ const toGet = (status2 === 301 || status2 === 302) && hop.method === "POST" || status2 === 303 && hop.method !== "GET" && hop.method !== "HEAD";
8838
+ const crossOrigin = next2.origin !== new URL(hop.url).origin;
8839
+ const headers = hop.headers.filter(
8840
+ ([name]) => !(toGet && BODY_HEADERS.has(name.toLowerCase())) && !(crossOrigin && CREDENTIALS.has(name.toLowerCase()))
8841
+ );
8842
+ return {
8843
+ url: withoutFragment(next2),
8844
+ method: toGet ? "GET" : hop.method,
8845
+ headers,
8846
+ body: toGet ? void 0 : hop.body
8847
+ };
8848
+ }
8849
+ function withMeta(response, url, redirected) {
8850
+ const clone = response.clone.bind(response);
8851
+ Object.defineProperty(response, "url", { value: url });
8852
+ Object.defineProperty(response, "redirected", { value: redirected });
8853
+ Object.defineProperty(response, "clone", { value: () => withMeta(clone(), url, redirected) });
8854
+ return response;
8855
+ }
8856
+ function bytesOf(chunk) {
8857
+ if (typeof chunk === "string") return new TextEncoder().encode(chunk);
8858
+ if (chunk instanceof ArrayBuffer) return new Uint8Array(chunk);
8859
+ if (ArrayBuffer.isView(chunk)) {
8860
+ return new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);
8861
+ }
8862
+ throw failed2(new TypeError("a request body chunk must be bytes or a string"));
8863
+ }
8864
+ async function bodyOf(request, cap, signal) {
8865
+ signal.throwIfAborted();
8866
+ if (!request.body || request.method === "GET" || request.method === "HEAD") return void 0;
8867
+ const reader = request.body.getReader();
8868
+ const stop = () => void reader.cancel(signal.reason).catch(() => void 0);
8869
+ signal.addEventListener("abort", stop, { once: true });
8870
+ const parts = [];
8871
+ let length = 0;
8872
+ try {
8873
+ for (; ; ) {
8874
+ const next2 = await reader.read().catch((err) => {
8875
+ throw signal.aborted ? signal.reason : failed2(err);
8876
+ });
8877
+ signal.throwIfAborted();
8878
+ if (next2.done) break;
8879
+ const chunk = bytesOf(next2.value);
8880
+ length += chunk.length;
8881
+ if (length > cap) {
8882
+ reader.cancel().catch(() => void 0);
8883
+ return OVER;
8884
+ }
8885
+ parts.push(chunk);
8886
+ }
8887
+ } finally {
8888
+ signal.removeEventListener("abort", stop);
8889
+ }
8890
+ if (length === 0) return void 0;
8891
+ const out = new Uint8Array(length);
8892
+ let at = 0;
8893
+ for (const part of parts) {
8894
+ out.set(part, at);
8895
+ at += part.length;
8896
+ }
8897
+ return out;
8898
+ }
8899
+ function fetchOp(kernel) {
8900
+ let traits;
8901
+ const traitsOf = () => {
8902
+ traits ??= kernel.json({ op: "net-traits" });
8903
+ traits.catch(() => {
8904
+ traits = void 0;
8905
+ });
8906
+ return traits;
8907
+ };
8908
+ const close = (handle) => kernel.raw({ op: "net-close", handle });
8909
+ const send = async (hop, signal) => {
8910
+ signal.throwIfAborted();
8911
+ const handle = await kernel.json({
8912
+ op: "net-open",
8913
+ url: hop.url,
8914
+ method: hop.method,
8915
+ headers: hop.headers,
8916
+ ...hop.body ? { body: hop.body } : {}
8917
+ });
8918
+ try {
8919
+ const r = await kernel.blocking({ op: "net-head", handle }, signal);
8920
+ signal.throwIfAborted();
8921
+ return r.ok && r.kind === "json" ? r.json : void 0;
8922
+ } catch (err) {
8923
+ await close(handle);
8924
+ throw signal.aborted ? signal.reason : failed2(err);
8925
+ }
8926
+ };
8927
+ const body = (handle, signal) => {
8928
+ let aborted;
8929
+ const settle = () => {
8930
+ if (aborted) signal.removeEventListener("abort", aborted);
8931
+ };
8932
+ return new ReadableStream(
8933
+ {
8934
+ start(controller) {
8935
+ aborted = () => {
8936
+ controller.error(signal.reason);
8937
+ void close(handle);
8938
+ };
8939
+ signal.addEventListener("abort", aborted, { once: true });
8940
+ },
8941
+ async pull(controller) {
8942
+ let r;
8943
+ try {
8944
+ signal.throwIfAborted();
8945
+ r = await kernel.blocking({ op: "net-read", handle, max: CHUNK }, signal);
8946
+ } catch (err) {
8947
+ settle();
8948
+ await close(handle);
8949
+ throw signal.aborted ? signal.reason : failed2(err);
8950
+ }
8951
+ const bytes = r.ok && r.kind === "bytes" ? r.bytes : new Uint8Array(0);
8952
+ if (bytes.length > 0) {
8953
+ controller.enqueue(bytes);
8954
+ return;
8955
+ }
8956
+ settle();
8957
+ controller.close();
8958
+ await close(handle);
8959
+ },
8960
+ cancel: async () => {
8961
+ settle();
8962
+ await close(handle);
8963
+ }
8964
+ },
8965
+ { highWaterMark: 0 }
8966
+ );
8967
+ };
8968
+ const respond = (head, method, redirected, encoded, signal) => {
8969
+ if (head.status < 200 || head.status > 599) {
8970
+ void close(head.handle);
8971
+ throw failed2(new JsCallError("EPROTO", `status ${head.status}`));
8972
+ }
8973
+ const empty = method === "HEAD" || NULL_BODY.has(head.status);
8974
+ if (empty) void close(head.handle);
8975
+ const headers = new Headers(head.headers);
8976
+ let stream = empty ? null : body(head.handle, signal);
8977
+ const coding = headers.get("content-encoding")?.trim().toLowerCase();
8978
+ if (stream && encoded && coding && DECODED.has(coding)) {
8979
+ const format = coding === "deflate" ? "deflate" : "gzip";
8980
+ stream = stream.pipeThrough(
8981
+ new DecompressionStream(format)
8982
+ );
8983
+ headers.delete("content-encoding");
8984
+ headers.delete("content-length");
8985
+ }
8986
+ const response = new Response(stream, {
8987
+ status: head.status,
8988
+ statusText: head.statusText,
8989
+ headers
8990
+ });
8991
+ return withMeta(response, head.url, redirected);
8992
+ };
8993
+ return async (input, init) => {
8994
+ const request = new Request(input, init);
8995
+ const { signal } = request;
8996
+ signal.throwIfAborted();
8997
+ const known = await traitsOf().catch((err) => {
8998
+ throw failed2(err);
8999
+ });
9000
+ if (!known.manualRedirects && request.redirect !== "follow") {
9001
+ throw failed2(new JsCallError("ENOTSUP", `redirect: ${request.redirect}`));
9002
+ }
9003
+ const url = withoutFragment(new URL(request.url));
9004
+ const bytes = await bodyOf(request, known.maxRequestBody, signal);
9005
+ if (bytes === OVER) {
9006
+ return withMeta(plain(413, `request body over ${known.maxRequestBody} bytes`), url, false);
9007
+ }
9008
+ let hop = {
9009
+ url,
9010
+ method: request.method,
9011
+ headers: [...request.headers],
9012
+ body: bytes
9013
+ };
9014
+ for (let hops = 0; ; hops++) {
9015
+ const head = await send(hop, signal);
9016
+ const location = head.headers.find(([name]) => name.toLowerCase() === "location")?.[1];
9017
+ const follow2 = known.manualRedirects && REDIRECTS.has(head.status) && location !== void 0 && request.redirect !== "manual";
9018
+ if (!follow2) {
9019
+ const redirected = hops > 0 || head.redirected === true;
9020
+ return respond(head, hop.method, redirected, known.encodedBodies, signal);
9021
+ }
9022
+ await close(head.handle);
9023
+ if (request.redirect === "error") throw failed2(new JsCallError("EREDIRECT", hop.url));
9024
+ if (hops >= MAX_REDIRECTS) throw failed2(new JsCallError("ELOOP", hop.url));
9025
+ hop = rewrite(hop, head.status, location);
9026
+ }
9027
+ };
9028
+ }
9029
+ var CHUNK, MAX_REDIRECTS, NULL_BODY, REDIRECTS, BODY_HEADERS, DECODED, CREDENTIALS, OVER;
9030
+ var init_js_fetch = __esm({
9031
+ "src/process/js/js-fetch.ts"() {
9032
+ "use strict";
9033
+ init_js_kernel();
9034
+ CHUNK = 64 * 1024;
9035
+ MAX_REDIRECTS = 20;
9036
+ NULL_BODY = /* @__PURE__ */ new Set([101, 103, 204, 205, 304]);
9037
+ REDIRECTS = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
9038
+ BODY_HEADERS = /* @__PURE__ */ new Set([
9039
+ "content-encoding",
9040
+ "content-language",
9041
+ "content-location",
9042
+ "content-type",
9043
+ "content-length"
9044
+ ]);
9045
+ DECODED = /* @__PURE__ */ new Set(["gzip", "x-gzip", "deflate"]);
9046
+ CREDENTIALS = /* @__PURE__ */ new Set(["authorization", "proxy-authorization", "cookie", "cookie2"]);
9047
+ OVER = /* @__PURE__ */ Symbol("over");
9048
+ }
9049
+ });
9050
+
8764
9051
  // src/process/js/js-io.ts
8765
9052
  function typeOf(info) {
8766
9053
  if (info.meta && "dir" in info.meta) return "directory";
@@ -8778,7 +9065,7 @@ function readDevice(info, max, random) {
8778
9065
  if (!dev) return void 0;
8779
9066
  if (dev.access === "write") throw new JsCallError("EBADF", "read");
8780
9067
  if (dev.device === "null") return new Uint8Array(0);
8781
- const out = new Uint8Array(Math.min(max, CHUNK));
9068
+ const out = new Uint8Array(Math.min(max, CHUNK2));
8782
9069
  if (dev.device === "urandom") random(out);
8783
9070
  return out;
8784
9071
  }
@@ -8839,12 +9126,12 @@ function openRequest(abs, o) {
8839
9126
  function index(n, what) {
8840
9127
  if (!Number.isSafeInteger(n) || n < 0) throw new JsCallError("EINVAL", what);
8841
9128
  }
8842
- var CHUNK, MAX_IO, O_WRONLY6, O_RDWR6, O_APPEND3;
9129
+ var CHUNK2, MAX_IO, O_WRONLY6, O_RDWR6, O_APPEND3;
8843
9130
  var init_js_io = __esm({
8844
9131
  "src/process/js/js-io.ts"() {
8845
9132
  "use strict";
8846
9133
  init_js_kernel();
8847
- CHUNK = 64 * 1024;
9134
+ CHUNK2 = 64 * 1024;
8848
9135
  MAX_IO = 1024 * 1024;
8849
9136
  O_WRONLY6 = 1;
8850
9137
  O_RDWR6 = 2;
@@ -8966,13 +9253,13 @@ function netOps(kernel, io) {
8966
9253
  const r = await kernel.raw({ op: "sock-connect", fd, addr, nonblock: true });
8967
9254
  if (!r.ok && r.errno !== "EINPROGRESS") throw new JsCallError(r.errno, "connect");
8968
9255
  await kernel.blocking({ op: "fd-select", read: [], write: [fd], timeoutMs: -1 }, signal);
8969
- const failed3 = await kernel.json({
9256
+ const failed4 = await kernel.json({
8970
9257
  op: "sock-getopt",
8971
9258
  fd,
8972
9259
  level: SOL_SOCKET,
8973
9260
  name: SO_ERROR
8974
9261
  });
8975
- if (failed3 !== 0) throw new JsCallError(errnoName(failed3), "connect");
9262
+ if (failed4 !== 0) throw new JsCallError(errnoName(failed4), "connect");
8976
9263
  return connection(fd);
8977
9264
  });
8978
9265
  }
@@ -9008,7 +9295,7 @@ function syncOps(kernel, shared) {
9008
9295
  infos.set(fd, got);
9009
9296
  return got;
9010
9297
  };
9011
- const read = (fd, max = CHUNK) => {
9298
+ const read = (fd, max = CHUNK2) => {
9012
9299
  index(max, "read");
9013
9300
  const emulated = readDevice(info(fd), max, shared.random);
9014
9301
  if (emulated) return emulated;
@@ -9217,7 +9504,7 @@ var init_js_sync = __esm({
9217
9504
  });
9218
9505
 
9219
9506
  // src/process/js/js-websocket.ts
9220
- function failed2(err) {
9507
+ function failed3(err) {
9221
9508
  return new TypeError("websocket failed", { cause: err });
9222
9509
  }
9223
9510
  function socketUrl(input) {
@@ -9261,7 +9548,7 @@ function websocketOp(kernel) {
9261
9548
  protocol = (r.ok && r.kind === "json" ? r.json : {}).protocol;
9262
9549
  } catch (err) {
9263
9550
  await free();
9264
- throw signal.aborted ? signal.reason : failed2(err);
9551
+ throw signal.aborted ? signal.reason : failed3(err);
9265
9552
  }
9266
9553
  let settle;
9267
9554
  let lose;
@@ -9311,7 +9598,7 @@ function websocketOp(kernel) {
9311
9598
  try {
9312
9599
  r = await kernel.blocking({ op: "net-ws-recv", handle }, stop.signal);
9313
9600
  } catch (err) {
9314
- hardStop(stop.signal.aborted ? stop.signal.reason : failed2(err));
9601
+ hardStop(stop.signal.aborted ? stop.signal.reason : failed3(err));
9315
9602
  throw stop.signal.reason;
9316
9603
  }
9317
9604
  stop.signal.throwIfAborted();
@@ -9416,7 +9703,7 @@ function createContext(o) {
9416
9703
  infos.set(fd, got);
9417
9704
  return got;
9418
9705
  };
9419
- const read = async (fd, max = CHUNK, signal) => {
9706
+ const read = async (fd, max = CHUNK2, signal) => {
9420
9707
  index(max, "read");
9421
9708
  const emulated = readDevice(await info(fd), max, random);
9422
9709
  if (emulated) return emulated;
@@ -9529,6 +9816,7 @@ function createContext(o) {
9529
9816
  reset: async (signal) => kernel.setHandler(signalNumber(signal), "default")
9530
9817
  },
9531
9818
  sync,
9819
+ fetch: fetchOp(kernel),
9532
9820
  ...children,
9533
9821
  net: netOps(kernel, io),
9534
9822
  websocket: websocketOp(kernel),
@@ -9665,6 +9953,7 @@ var init_js_context = __esm({
9665
9953
  init_signals();
9666
9954
  init_sync_fs_wire();
9667
9955
  init_js_children();
9956
+ init_js_fetch();
9668
9957
  init_js_io();
9669
9958
  init_js_kernel();
9670
9959
  init_js_net();
@@ -9870,20 +10159,20 @@ function started(init, port3, run, wasi, js) {
9870
10159
  return run(wasmInit, port3);
9871
10160
  }
9872
10161
  function processEntry(port3, run = runWasmProcess, wasi = loadWasi, js = loadJs) {
9873
- const failed3 = (err) => port3.postMessage({
10162
+ const failed4 = (err) => port3.postMessage({
9874
10163
  type: WASM_PROCESS_ERROR,
9875
10164
  message: err instanceof Error ? err.stack ?? err.message : String(err)
9876
10165
  });
9877
10166
  return (data) => {
9878
10167
  const type = data?.type;
9879
10168
  if (type === WASM_THREAD_INIT) {
9880
- wasi().then((m) => m.runWasiThread(data, port3)).catch(failed3);
10169
+ wasi().then((m) => m.runWasiThread(data, port3)).catch(failed4);
9881
10170
  return;
9882
10171
  }
9883
10172
  if (type !== WASM_PROCESS_INIT) return;
9884
10173
  started(data, port3, run, wasi, js).then(
9885
10174
  (code2) => port3.postMessage({ type: WASM_PROCESS_EXIT, code: code2 }),
9886
- failed3
10175
+ failed4
9887
10176
  );
9888
10177
  };
9889
10178
  }