@ai-ecoverse/slicc-kernel 1.5.0 → 1.6.1

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.
@@ -14,7 +14,7 @@ var __export = (target, all) => {
14
14
  };
15
15
 
16
16
  // src/kernel/protocol.ts
17
- var WASM_PROCESS_INIT, WASM_PROCESS_EXIT, WASM_PROCESS_ERROR, WASM_THREAD_SPAWN, WASM_THREAD_INIT, WASM_THREAD_EXIT, WASM_MAX_THREADS;
17
+ var WASM_PROCESS_INIT, WASM_PROCESS_EXIT, WASM_PROCESS_ERROR, WASM_THREAD_SPAWN, WASM_THREAD_INIT, WASM_THREAD_EXIT, WASM_MAX_THREADS, WASM_DEFAULT_THREADS;
18
18
  var init_protocol = __esm({
19
19
  "src/kernel/protocol.ts"() {
20
20
  "use strict";
@@ -24,7 +24,8 @@ var init_protocol = __esm({
24
24
  WASM_THREAD_SPAWN = "wasm-thread-spawn";
25
25
  WASM_THREAD_INIT = "wasm-thread-init";
26
26
  WASM_THREAD_EXIT = "wasm-thread-exit";
27
- WASM_MAX_THREADS = 64;
27
+ WASM_MAX_THREADS = 256;
28
+ WASM_DEFAULT_THREADS = 64;
28
29
  }
29
30
  });
30
31
 
@@ -468,7 +469,7 @@ function createLiveVfsPlugin(Fs) {
468
469
  };
469
470
  }
470
471
  function ownedBy(plugin, node) {
471
- return !!node && plugin.mounts.has(node.mount);
472
+ return !!node?.live && plugin.mounts.has(node.mount);
472
473
  }
473
474
  function flushLiveVfs(Fs, plugin) {
474
475
  for (const head of Fs.nameTable ?? []) {
@@ -494,7 +495,7 @@ function invalidateLiveVfs(Fs, plugin) {
494
495
  s.stat = void 0;
495
496
  s.listed = void 0;
496
497
  if (s.openCount === 0) {
497
- if (node !== node.mount.root) drop.push(node);
498
+ if (node !== node.mount.root && !node.mounted) drop.push(node);
498
499
  } else if (s.loaded && !s.dirty) {
499
500
  s.data = void 0;
500
501
  s.len = 0;
@@ -515,6 +516,7 @@ function describeMountError(err) {
515
516
  return typeof errno2 === "number" ? `errno ${errno2}` : String(err);
516
517
  }
517
518
  function mountLiveVfsDirs(Fs, bridge, dirs, warn) {
519
+ if (Fs.root?.memfs) Fs.root.node_ops = Fs.root.memfs;
518
520
  if (typeof Fs.filesystems !== "object" || !Fs.filesystems) {
519
521
  throw new Error(
520
522
  "the module was linked without filesystem support, so the VFS cannot be mounted (link it with -sFORCE_FILESYSTEM=1)"
@@ -535,6 +537,55 @@ function mountLiveVfsDirs(Fs, bridge, dirs, warn) {
535
537
  }
536
538
  return { plugin, mounted };
537
539
  }
540
+ function liveRoot(Fs, bridge) {
541
+ const root = Fs.root;
542
+ const plugin = Fs.filesystems.SLICC_LIVE_FS;
543
+ if (!root || !plugin) return;
544
+ root.mount.opts = { root: "/", bridge };
545
+ root.live = { len: 0, loaded: false, dirty: false, openCount: 0 };
546
+ plugin.mounts.add(root.mount);
547
+ invalidateLiveVfs(Fs, plugin);
548
+ guardRenames(Fs);
549
+ const memfs = root.memfs ?? root.node_ops;
550
+ const live = plugin.node_ops;
551
+ root.memfs = memfs;
552
+ const own = (name) => Object.hasOwn(root.contents ?? {}, name);
553
+ root.node_ops = {
554
+ ...memfs,
555
+ lookup: (parent, name) => live.lookup(parent, name),
556
+ mknod: (parent, name, mode, dev) => live.mknod(parent, name, mode, dev),
557
+ unlink: (parent, name) => live.unlink(parent, name),
558
+ rmdir: (parent, name) => (own(name) ? memfs : live).rmdir(parent, name),
559
+ symlink: (parent, name, target) => live.symlink(parent, name, target),
560
+ rename: (node, dir, name) => (node.live ? live : memfs).rename(node, dir, name),
561
+ readdir(node) {
562
+ const names = new Set(memfs.readdir(node));
563
+ for (const name of live.readdir(node)) names.add(name);
564
+ return [...names];
565
+ }
566
+ };
567
+ }
568
+ function crosses(Fs, from, to) {
569
+ const parentOf = (path) => Fs.lookupPath?.(path, { parent: true }).node;
570
+ const name = from.replace(/\/+$/, "").split("/").pop() ?? "";
571
+ try {
572
+ const fromDir = parentOf(from);
573
+ const node = fromDir && Fs.lookupNode?.(fromDir, name);
574
+ const dir = parentOf(to);
575
+ return !!node && !!dir && !!node.live !== !!dir.live;
576
+ } catch {
577
+ return false;
578
+ }
579
+ }
580
+ function guardRenames(Fs) {
581
+ const rename = Fs.rename?.bind(Fs);
582
+ if (!rename || Fs.sliccRename) return;
583
+ Fs.sliccRename = true;
584
+ Fs.rename = (from, to) => {
585
+ if (crosses(Fs, from, to)) throw new Fs.ErrnoError(ERRNO_BY_CODE.EXDEV);
586
+ rename(from, to);
587
+ };
588
+ }
538
589
  var ERRNO_BY_CODE, EIO, S_IFDIR, S_IFREG, S_IFLNK, PERM_MASK, DEFAULT_DIR_PERM, UMASK, SEEK_CUR, SEEK_END;
539
590
  var init_live_vfs_fs = __esm({
540
591
  "src/realm/live-vfs-fs.ts"() {
@@ -579,7 +630,7 @@ function topLevelDirs(bridge, warn) {
579
630
  names = bridge.readdir("/");
580
631
  } catch (err) {
581
632
  warn(`cannot list the VFS root, nothing mounted: ${String(err)}`);
582
- return [];
633
+ return void 0;
583
634
  }
584
635
  const candidates = names.filter((name) => name && !name.includes("/") && !MODULE_OWNED_DIRS.has(name)).map((name) => `/${name}`);
585
636
  for (const dir of SYNTHETIC_DIRS) if (!candidates.includes(dir)) candidates.push(dir);
@@ -594,7 +645,9 @@ function topLevelDirs(bridge, warn) {
594
645
  }
595
646
  function mountVfsIntoEmscripten(Fs, deps) {
596
647
  const { bridge, warn } = deps;
597
- const { plugin, mounted } = mountLiveVfsDirs(Fs, bridge, topLevelDirs(bridge, warn), warn);
648
+ const dirs = topLevelDirs(bridge, warn);
649
+ const { plugin, mounted } = mountLiveVfsDirs(Fs, bridge, dirs ?? [], warn);
650
+ if (dirs) liveRoot(Fs, bridge);
598
651
  try {
599
652
  Fs.chdir(deps.cwd);
600
653
  } catch (err) {
@@ -1625,6 +1678,28 @@ function wrapCloexecSyscalls(imports, glue, deps) {
1625
1678
  }
1626
1679
  }
1627
1680
  }
1681
+ function persistsItself(stream) {
1682
+ const type = stream.node.mount?.type;
1683
+ return typeof type?.syncfs === "function";
1684
+ }
1685
+ function syncFsync(imports, fs) {
1686
+ for (const namespace of Object.values(imports)) {
1687
+ const original = namespace?.fd_sync;
1688
+ if (typeof original !== "function" || !original.isAsync) continue;
1689
+ namespace.fd_sync = (fd) => {
1690
+ const stream = fs()?.getStream(fd);
1691
+ if (!stream) return EBADF;
1692
+ if (persistsItself(stream)) return original(fd);
1693
+ try {
1694
+ const result = stream.stream_ops.fsync?.(stream);
1695
+ return typeof result === "number" ? result : 0;
1696
+ } catch (err) {
1697
+ const { errno: errno2, code: code2 } = err;
1698
+ return typeof errno2 === "number" ? errno2 : wasiErrno(String(code2));
1699
+ }
1700
+ };
1701
+ }
1702
+ }
1628
1703
  function wasmMemory(instance, imports) {
1629
1704
  const isMemory = (v) => v instanceof WebAssembly.Memory;
1630
1705
  const exported = Object.values(instance.exports).find(isMemory);
@@ -1719,7 +1794,7 @@ function useDevFd(Fs) {
1719
1794
  return fstat.call(Fs, fd);
1720
1795
  };
1721
1796
  }
1722
- var O_CLOEXEC, FD_CLOEXEC, F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_DUPFD_CLOEXEC, tracked, IMPORT_NAMES, DIR_MODE, LINK_MODE;
1797
+ var O_CLOEXEC, FD_CLOEXEC, F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_DUPFD_CLOEXEC, tracked, IMPORT_NAMES, EBADF, DIR_MODE, LINK_MODE;
1723
1798
  var init_process_fds = __esm({
1724
1799
  "src/process/process-fds.ts"() {
1725
1800
  "use strict";
@@ -1742,6 +1817,7 @@ var init_process_fds = __esm({
1742
1817
  ioctl: "__syscall_ioctl",
1743
1818
  setitimer: "_setitimer_js"
1744
1819
  };
1820
+ EBADF = 8;
1745
1821
  DIR_MODE = 16749;
1746
1822
  LINK_MODE = 41408;
1747
1823
  }
@@ -2402,6 +2478,7 @@ async function runWasmProcess(init, port, deps = {}) {
2402
2478
  }
2403
2479
  }
2404
2480
  });
2481
+ syncFsync(imports, () => ownValue(module, "FS"));
2405
2482
  return WebAssembly.instantiate(init.program.module, imports);
2406
2483
  }).then((instance) => {
2407
2484
  memory = wasmMemory(instance, imports);
@@ -4255,6 +4332,7 @@ function importsContext({
4255
4332
  fs,
4256
4333
  fds,
4257
4334
  syscall: call2,
4335
+ ...processes(host, call2),
4258
4336
  async: {
4259
4337
  submit: (req) => call2({ op: "async-submit", req }),
4260
4338
  wait(timeoutMs) {
@@ -4284,13 +4362,69 @@ function importsContext({
4284
4362
  errno: (err) => wasiErrnoOf(code(err))
4285
4363
  };
4286
4364
  }
4287
- var UID;
4365
+ function processes(host, call2) {
4366
+ const close = (fd) => void call2({ op: "fd-close", fd });
4367
+ const slot = (n, how, mine, theirs) => {
4368
+ if (how === "inherit") return { fd: n };
4369
+ if (how === "null") return { none: true };
4370
+ const [read, write] = call2({ op: "fd-pipe" });
4371
+ mine[n] = n === 0 ? write : read;
4372
+ theirs.push(n === 0 ? read : write);
4373
+ return { fd: n === 0 ? read : write };
4374
+ };
4375
+ return {
4376
+ spawn(o) {
4377
+ const mine = [];
4378
+ const theirs = [];
4379
+ host.fds.promoteFiles();
4380
+ try {
4381
+ const stdio = STDIO.map((name, n) => slot(n, o[name] ?? "inherit", mine, theirs));
4382
+ const pid = call2({
4383
+ op: "proc-spawn",
4384
+ file: o.argv[0],
4385
+ argv: o.argv,
4386
+ env: o.env ?? { ...host.o.env },
4387
+ cwd: o.cwd ?? host.cwd,
4388
+ stdio
4389
+ });
4390
+ const out = { pid };
4391
+ STDIO.forEach((name, n) => {
4392
+ if (mine[n] !== void 0) out[name] = mine[n];
4393
+ });
4394
+ return out;
4395
+ } catch (err) {
4396
+ for (const fd of mine) if (fd !== void 0) close(fd);
4397
+ throw err;
4398
+ } finally {
4399
+ for (const fd of theirs) close(fd);
4400
+ host.o.fs.invalidate?.();
4401
+ }
4402
+ },
4403
+ wait(pid) {
4404
+ for (; ; ) {
4405
+ try {
4406
+ const [, status2] = call2({ op: "proc-wait", pid, nohang: false });
4407
+ host.o.fs.invalidate?.();
4408
+ const signal = status2 & 127;
4409
+ return signal ? { status: 128 + signal, signal } : { status: status2 >> 8 & 255 };
4410
+ } catch (err) {
4411
+ if (code(err) !== "EINTR") throw err;
4412
+ }
4413
+ }
4414
+ },
4415
+ kill(pid, sig) {
4416
+ call2({ op: "proc-kill", pid, sig });
4417
+ }
4418
+ };
4419
+ }
4420
+ var UID, STDIO;
4288
4421
  var init_wasi_imports = __esm({
4289
4422
  "src/process/wasi/wasi-imports.ts"() {
4290
4423
  "use strict";
4291
4424
  init_wasi_abi();
4292
4425
  init_wasi_files();
4293
4426
  UID = 1e3;
4427
+ STDIO = ["stdin", "stdout", "stderr"];
4294
4428
  }
4295
4429
  });
4296
4430
 
@@ -4409,7 +4543,7 @@ var init_wasi_stats = __esm({
4409
4543
  // src/process/wasi/wasi-threads.ts
4410
4544
  function threadCap(env) {
4411
4545
  const asked = Number.parseInt(env.SLICC_WASM_THREADS ?? "", 10);
4412
- return asked >= 1 ? Math.min(asked, WASM_MAX_THREADS) : WASM_MAX_THREADS;
4546
+ return asked >= 1 ? Math.min(asked, WASM_MAX_THREADS) : WASM_DEFAULT_THREADS;
4413
4547
  }
4414
4548
  var LAST_TID, RUNNING, MAIN_TID, ThreadExit, WasiThreads;
4415
4549
  var init_wasi_threads = __esm({