@ai-ecoverse/slicc-kernel 1.26.4 → 1.26.5

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/README.md CHANGED
@@ -300,7 +300,7 @@ Programs mount and unmount with `mount(2)` and `umount2(2)`, so a `mount`/`umoun
300
300
 
301
301
  ### Exec
302
302
 
303
- An exec'd program takes over the pid of the process it replaces, as on Linux: `getpid()` and `$$` in the new image, `/proc`, `ps`, `kill` and the parent's `waitpid` all agree on that pid, and the image's parent pid is the replaced process's. Its own children see that pid as their parent. Signals a program ignores stay ignored in the image it execs and in the children it spawns or forks, as POSIX has it, so `nohup cmd` and `trap '' TERM; exec cmd` keep `cmd` safe from them; caught signals go back to their default. The kernel holds what was handed down, so a new image that sets one of those signals back to the default with `signal(SIG_DFL)` still ignores it, until it installs a handler.
303
+ An exec'd program takes over the pid of the process it replaces, as on Linux: `getpid()` and `$$` in the new image, `/proc`, `ps`, `kill` and the parent's `waitpid` all agree on that pid, and the image's parent pid is the replaced process's. Its own children see that pid as their parent. A file removed or renamed over while programs hold it open keeps its bytes for them, as on Linux: the kernel keeps one copy for all holders, shared by their descriptors (writes through one are seen through the others), and frees it when the last one closes. Signals a program ignores stay ignored in the image it execs and in the children it spawns or forks, as POSIX has it, so `nohup cmd` and `trap '' TERM; exec cmd` keep `cmd` safe from them; caught signals go back to their default. The kernel holds what was handed down, so a new image that sets one of those signals back to the default with `signal(SIG_DFL)` still ignores it, until it installs a handler.
304
304
 
305
305
  - **Emscripten:** `Module.sliccKernel.execve(file, argv, env, cwd)` runs `file` as this process's new image on its fds 0, 1 and 2, waits for it, and returns its wait status, or a negative errno when it cannot start. `env` and `cwd` may be `null` for this process's own. An exec shim detects it with `typeof Module.sliccKernel.execve === 'function'` and exits with the status it returns, as `execve` never returns on success. Older shims spawn the program and then call `Module.sliccKernel.execWait(pid)`; that still works, but the image then reports a pid of its own from `getpid()`.
306
306
  - **WASIX:** `proc_exec` does this by itself.
@@ -6919,8 +6919,10 @@ var VfsNodes = class {
6919
6919
  for (const [p, node] of this.byPath) if (within3(p, path)) await node.serial(() => node.flush());
6920
6920
  }
6921
6921
  async unlinking(path) {
6922
- const node = this.byPath.get(path);
6923
- if (node) await node.serial(async () => void await Promise.all([node.keep(), node.limit()]));
6922
+ for (const [held, node] of [...this.byPath]) {
6923
+ if (!within3(held, path)) continue;
6924
+ await node.serial(async () => void await Promise.all([node.keep(), node.limit()]));
6925
+ }
6924
6926
  }
6925
6927
  revoke(prefix) {
6926
6928
  for (const [path, node] of this.byPath) {
@@ -6930,10 +6932,11 @@ var VfsNodes = class {
6930
6932
  }
6931
6933
  }
6932
6934
  unlinked(path) {
6933
- const node = this.byPath.get(path);
6934
- if (!node) return;
6935
- node.orphaned = true;
6936
- this.byPath.delete(path);
6935
+ for (const [held, node] of [...this.byPath]) {
6936
+ if (!within3(held, path)) continue;
6937
+ node.orphaned = true;
6938
+ this.byPath.delete(held);
6939
+ }
6937
6940
  }
6938
6941
  renamed(from, to) {
6939
6942
  if (from === to) return;
@@ -7007,6 +7010,23 @@ async function refuseReadonly(fs, path, flags, opts = {}) {
7007
7010
  const st = own ?? await stat(await targetDir(fs, path));
7008
7011
  if (st?.readonly) throw new KernelError("EROFS");
7009
7012
  }
7013
+ function keepingOpen(fs, nodes) {
7014
+ return {
7015
+ ...fs,
7016
+ async rm(path, options) {
7017
+ const at = fs.resolvePath("/", path);
7018
+ await nodes.unlinking(at);
7019
+ await fs.rm(path, options);
7020
+ nodes.unlinked(at);
7021
+ },
7022
+ async rename(from, to) {
7023
+ const [a, b] = [fs.resolvePath("/", from), fs.resolvePath("/", to)];
7024
+ await nodes.unlinking(b);
7025
+ await fs.rename(from, to);
7026
+ nodes.renamed(a, b);
7027
+ }
7028
+ };
7029
+ }
7010
7030
  function vfsFile(fs, opts, nodes) {
7011
7031
  const access = opts.flags & O_ACCMODE;
7012
7032
  const readable = access !== O_WRONLY;
@@ -7202,8 +7222,8 @@ var WasmProcess = class {
7202
7222
  this.options = options;
7203
7223
  this.inherited = options.ignored ?? 0;
7204
7224
  this.children = new ChildTable(fds, options.spawner, options.forker);
7205
- this.nodes = new VfsNodes(options.fs);
7206
- options.openFiles?.add(this.nodes);
7225
+ this.nodes = options.nodes ?? new VfsNodes(options.fs);
7226
+ if (!options.nodes) options.openFiles?.add(this.nodes);
7207
7227
  this.children.onChildState = () => this.signal(SIG.CHLD);
7208
7228
  this.children.onReap = options.onReap;
7209
7229
  }
@@ -7706,7 +7726,7 @@ var WasmProcess = class {
7706
7726
  this.asyncOps.close();
7707
7727
  for (const pid of this.children.pids()) this.options.onReap?.(pid);
7708
7728
  await this.fds.closeAll();
7709
- this.options.openFiles?.delete(this.nodes);
7729
+ if (!this.options.nodes) this.options.openFiles?.delete(this.nodes);
7710
7730
  await this.options.http?.closeAll();
7711
7731
  }
7712
7732
  };
@@ -7756,6 +7776,7 @@ function spawnWasmProcess(opts) {
7756
7776
  kill: opts.kill,
7757
7777
  processes: opts.processes,
7758
7778
  openFiles: opts.openFiles,
7779
+ ...opts.nodes ? { nodes: opts.nodes } : {},
7759
7780
  mounts: opts.mounts,
7760
7781
  ...opts.mount ? { mount: opts.mount } : {},
7761
7782
  ...opts.umount ? { umount: opts.umount } : {},
@@ -9314,6 +9335,7 @@ var Launcher = class {
9314
9335
  fstabRetries;
9315
9336
  inserted = /* @__PURE__ */ new Map();
9316
9337
  openFiles = /* @__PURE__ */ new Set();
9338
+ nodes;
9317
9339
  held = /* @__PURE__ */ new Set();
9318
9340
  processMounts;
9319
9341
  booting = new AbortController();
@@ -9347,7 +9369,10 @@ var Launcher = class {
9347
9369
  ca: this.ca
9348
9370
  });
9349
9371
  enableCdp(this.net, this.cdp);
9350
- this.fs = withCommandDirs(this.base, async () => new Set((await this.commands()).keys()));
9372
+ const fs = withCommandDirs(this.base, async () => new Set((await this.commands()).keys()));
9373
+ this.nodes = new VfsNodes(fs);
9374
+ this.openFiles.add(this.nodes);
9375
+ this.fs = keepingOpen(fs, this.nodes);
9351
9376
  this.watchers.watch([this.modulesDir, this.pnpmHome], { recursive: true }, () => {
9352
9377
  this.catalog = void 0;
9353
9378
  });
@@ -9520,6 +9545,7 @@ var Launcher = class {
9520
9545
  kill: (target, sig) => this.kill(target, sig),
9521
9546
  processes: () => ({ boot: this.boot, processes: this.list() }),
9522
9547
  openFiles: this.openFiles,
9548
+ nodes: this.nodes,
9523
9549
  held: this.held,
9524
9550
  statfs: (path) => this.mounts.statfs(path),
9525
9551
  mounts: () => this.mounts.list(),