@ai-ecoverse/slicc-kernel 1.134.1 → 1.134.3

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
@@ -1096,8 +1096,8 @@ The kernel writes `/etc/passwd` and `/etc/group` when it starts (see [Users](#us
1096
1096
  ### How many processes at once
1097
1097
 
1098
1098
  In a browser every process worker of the page shares one renderer. V8 reserves about 8 GiB of address space for each 32-bit wasm memory, whatever its declared maximum, and its sandbox holds about 1 TiB. So a page runs about 125 wasm processes (or programs that own a wasm memory) at once, counting everything in the renderer (#970). Node has no such ceiling, and neither does Linux. The kernel keeps processes inside that ceiling:
1099
- - **The ceiling:** 112 by default in a browser and none in Node. It's the kernel's count of live wasm processes, with the kernel's other wasm memories in the page left outside it. When an instantiation runs out of memory anyway, the kernel learns the real ceiling at that moment (the live count minus one), and that learned value wins over the default. A learned ceiling is never below 16, since an OOM at a low count means something outside it (another tab in the same renderer) filled the renderer. It's raised by 8 for each minute without another OOM, back to the default.
1100
- - **Admission:** a spawn, fork, exec or `kernel.run` at the ceiling waits for another process to exit. It keeps waiting as long as processes exit or are admitted, and fails with `EAGAIN` only after 10 s with neither. A long `make -j` or `xargs -P` therefore queues, and a pipeline that needs more live processes than the ceiling fails cleanly. bash's own retry on a fork's `EAGAIN` (`fork: retry: Resource temporarily unavailable`) handles the rest.
1099
+ - **The ceiling:** 112 by default in a browser and none in Node (`createNodeKernel({ wasmMemories: { ceiling, idleMs } })` sets one in Node; `idleMs`, the quiet spell before `EAGAIN` below, 10 s by default, is there for tests). It's the kernel's count of live wasm processes, with the kernel's other wasm memories in the page left outside it. When an instantiation runs out of memory anyway, the kernel learns the real ceiling at that moment (the live count minus one), and that learned value wins over the default. A learned ceiling is never below 16, since an OOM at a low count means something outside it (another tab in the same renderer) filled the renderer. It's raised by 8 for each minute without another OOM, back to the default.
1100
+ - **Admission:** a spawn, fork, exec or `kernel.run` at the ceiling waits for another process to exit. It keeps waiting as long as processes exit, are admitted or finish starting (a process becoming ready counts, so a slow host that is still booting the processes ahead of it doesn't fail the spawn, #1196), and fails with `EAGAIN` only after 10 s with none of these. A long `make -j` or `xargs -P` therefore queues, and a pipeline that needs more live processes than the ceiling fails cleanly. bash's own retry on a fork's `EAGAIN` (`fork: retry: Resource temporarily unavailable`) handles the rest.
1101
1101
  - **Close to the ceiling** (within 16 of it), the kernel waits for each new process to finish instantiating before the spawn returns. If it ran out of memory, the kernel starts it again, quietly, once there's room, so the caller sees no failure.
1102
1102
  - **The rare residual case:** a process that fails to instantiate with nobody waiting on it, which happens only when something outside the count fills the renderer. It ends with status 126 and `<program>: cannot allocate memory for a new process (too many processes at once)` on its stderr, never a JS `RangeError`.
1103
1103
  - **Below a learned ceiling,** a process that still runs out of memory is started again once another process exits, and the spawn fails with `EAGAIN` after 10 s with none.
@@ -2378,14 +2378,14 @@ var OpfsFs = class {
2378
2378
  const staged = resolvePath(parent.path, staging);
2379
2379
  const place = async () => {
2380
2380
  this.forget(destination);
2381
- const timed2 = await this.explicitTimes(source.path);
2381
+ const copies = /* @__PURE__ */ new Map();
2382
2382
  const root = { ino: inodeOf(source.path), ...moving };
2383
2383
  const owned4 = lock ? { lock } : {};
2384
2384
  const first = copying ? await this.intend({ from: source.path, to: staged, root, ...owned4 }) : void 0;
2385
2385
  const second = copying && swap ? await this.intend({ from: staged, to: destination, replace: true, root, ...owned4 }) : void 0;
2386
2386
  const moved2 = await this.replacingTarget(
2387
2387
  targetStat !== null,
2388
- () => this.place(source.handle, dir, staging)
2388
+ () => this.place(source.handle, dir, staging, copies)
2389
2389
  ).catch(async (err) => {
2390
2390
  if (first) await this.rollBack(staged, source.path, [first, second]);
2391
2391
  throw err;
@@ -2399,15 +2399,13 @@ var OpfsFs = class {
2399
2399
  await this.meta.update(source.path, () => left);
2400
2400
  }
2401
2401
  if (first) await this.meta.update(first, () => void 0);
2402
- let copied = !moved2;
2403
2402
  if (swap) {
2404
2403
  const hidden = await dir.getDirectoryHandle(staging);
2405
- const placed = await this.place(hidden, dir, name2);
2404
+ const placed = await this.place(hidden, dir, name2, copies);
2406
2405
  if (!placed) await dir.removeEntry(staging, { recursive: true });
2407
- copied ||= !placed;
2408
2406
  }
2409
2407
  if (second) await this.meta.update(second, () => void 0);
2410
- if (copied) await this.restamp(destination, timed2);
2408
+ await this.restamp(destination, copies);
2411
2409
  this.changed(source.path, destination);
2412
2410
  this.touch(Date.now(), parentOf3(source.path), parent.path);
2413
2411
  };
@@ -2624,22 +2622,17 @@ var OpfsFs = class {
2624
2622
  const handle = await this.handle(path);
2625
2623
  return handle.kind === "file" ? (await this.snapshot(handle)).lastModified : 0;
2626
2624
  }
2627
- async explicitTimes(path) {
2628
- const timed2 = [];
2629
- for (const entry of await this.meta.under(path)) {
2630
- if (entry.mtimeFor === void 0 || entry.link !== void 0) continue;
2631
- const current = await this.modified(entry.path).catch(() => void 0);
2632
- if (current === entry.mtimeFor) timed2.push(entry.path.slice(path.length));
2633
- }
2634
- return timed2;
2635
- }
2636
- async restamp(path, timed2) {
2637
- for (const rest2 of timed2) {
2638
- const mtimeFor = await this.modified(path + rest2);
2625
+ async restamp(path, copies) {
2626
+ if (copies.size === 0) return;
2627
+ const copied = [...copies];
2628
+ const entries = await this.meta.get(copied.map(([rest2]) => path + rest2));
2629
+ for (const [i, [rest2, { before, made: made2 }]] of copied.entries()) {
2630
+ if (entries[i]?.mtimeFor !== before) continue;
2631
+ const mtimeFor = (await this.io(made2.getFile())).lastModified;
2639
2632
  await this.meta.update(path + rest2, (entry) => entry && { ...entry, mtimeFor });
2640
2633
  }
2641
2634
  }
2642
- async place(handle, dir, name2) {
2635
+ async place(handle, dir, name2, copies) {
2643
2636
  const move = handle.move;
2644
2637
  if (move) this.others++;
2645
2638
  const moved2 = await move?.call(handle, dir, name2).then(
@@ -2649,7 +2642,7 @@ var OpfsFs = class {
2649
2642
  if (moved2) return true;
2650
2643
  const before = this.fileMoves;
2651
2644
  try {
2652
- await this.copy(handle, dir, name2);
2645
+ await this.copy(handle, dir, name2, copies);
2653
2646
  } catch (err) {
2654
2647
  if (handle.kind === "directory" && this.fileMoves === before) {
2655
2648
  await this.io(dir.removeEntry(name2, { recursive: true }));
@@ -2659,7 +2652,7 @@ var OpfsFs = class {
2659
2652
  return false;
2660
2653
  }
2661
2654
  fileMoves = 0;
2662
- async copy(handle, dir, name2) {
2655
+ async copy(handle, dir, name2, copies, rest2 = "") {
2663
2656
  if (handle.kind === "file" && movable(handle)) {
2664
2657
  this.others++;
2665
2658
  const moved2 = await handle.move?.(dir, name2).then(
@@ -2674,13 +2667,17 @@ var OpfsFs = class {
2674
2667
  if (handle.kind === "file") {
2675
2668
  const made2 = await this.io(dir.getFileHandle(name2, { create: true }));
2676
2669
  const writable2 = await this.io(made2.createWritable());
2677
- await writable2.write(await this.io(handle.getFile()));
2670
+ const file = await this.io(handle.getFile());
2671
+ await writable2.write(file);
2678
2672
  await writable2.close();
2673
+ copies?.set(rest2, { before: copies.get(rest2)?.before ?? file.lastModified, made: made2 });
2679
2674
  return;
2680
2675
  }
2681
2676
  const target = await this.io(dir.getDirectoryHandle(name2, { create: true }));
2682
2677
  this.others++;
2683
- for await (const child of handle.values()) await this.copy(child, target, child.name);
2678
+ for await (const child of handle.values()) {
2679
+ await this.copy(child, target, child.name, copies, `${rest2}/${child.name}`);
2680
+ }
2684
2681
  }
2685
2682
  async symlink(target, path, owner) {
2686
2683
  const parent = await this.locate(parentOf3(path), true);
@@ -7101,7 +7098,7 @@ function satisfies(version, range2) {
7101
7098
  }
7102
7099
 
7103
7100
  // src/version.ts
7104
- var KERNEL_VERSION = true ? "1.134.1" : "0.0.0-dev";
7101
+ var KERNEL_VERSION = true ? "1.134.3" : "0.0.0-dev";
7105
7102
  var OS_RELEASE = "6.0.0-slicc";
7106
7103
  function procVersion() {
7107
7104
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -24772,6 +24769,9 @@ var WasmMemories = class {
24772
24769
  const source = this.learned ? "learned" : ceiling === void 0 ? "none" : "default";
24773
24770
  return { live: this.live, ceiling: ceiling ?? 0, source };
24774
24771
  }
24772
+ started() {
24773
+ this.progress();
24774
+ }
24775
24775
  ended() {
24776
24776
  this.live = Math.max(0, this.live - 1);
24777
24777
  this.progress();
@@ -28088,6 +28088,7 @@ var Launcher = class {
28088
28088
  });
28089
28089
  const counted2 = (handle2) => {
28090
28090
  void handle2.exited.finally(() => this.memories.ended());
28091
+ void Promise.resolve(handle2.ready).then(() => this.memories.started());
28091
28092
  return handle2;
28092
28093
  };
28093
28094
  if (!this.memories.near()) {