@ai-ecoverse/slicc-kernel 1.124.1 → 1.124.2

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
@@ -942,11 +942,14 @@ The kernel writes `/etc/passwd` and `/etc/group` when it starts (see [Users](#us
942
942
  ### How many processes at once
943
943
 
944
944
  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:
945
- - **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.
945
+ - **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.
946
946
  - **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.
947
947
  - **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.
948
948
  - **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`.
949
- - **`/proc/sys/kernel/slicc_wasm_memories`** reads `<live> <ceiling>` (the ceiling 0 for none).
949
+ - **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.
950
+ - **`/proc/sys/kernel/slicc_wasm_memories`** reads `<live> <ceiling> <source>`. The source is `default`, `learned`, or `none` (with the ceiling 0).
951
+
952
+ `/proc/sys/kernel/slicc_shared_root` reads `1` while another kernel shares the root (a tab, or a second kernel in the page) and `0` otherwise. A peer's tab that closes is noticed when this kernel next writes to a shared file, at most every 30 s, so the value can stay `1` for a while after a peer has gone.
950
953
 
951
954
  ### Metadata
952
955
 
@@ -6565,7 +6565,7 @@ function satisfies(version, range2) {
6565
6565
  }
6566
6566
 
6567
6567
  // src/version.ts
6568
- var KERNEL_VERSION = true ? "1.124.1" : "0.0.0-dev";
6568
+ var KERNEL_VERSION = true ? "1.124.2" : "0.0.0-dev";
6569
6569
  var OS_RELEASE = "6.0.0-slicc";
6570
6570
  function procVersion() {
6571
6571
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -12721,7 +12721,9 @@ var SYS_TREE = {
12721
12721
  osrelease: `${OS_RELEASE}
12722
12722
  `,
12723
12723
  ostype: "Linux\n",
12724
- slicc_wasm_memories: (listing) => `${listing.wasm?.live ?? 0} ${listing.wasm?.ceiling ?? 0}
12724
+ slicc_wasm_memories: (listing) => `${listing.wasm?.live ?? 0} ${listing.wasm?.ceiling ?? 0} ${listing.wasm?.source ?? "none"}
12725
+ `,
12726
+ slicc_shared_root: (listing) => `${listing.peers ?? 0}
12725
12727
  `
12726
12728
  }
12727
12729
  };
@@ -21926,37 +21928,65 @@ var SettlingChildren = class {
21926
21928
 
21927
21929
  // src/kernel/wasm-memories.ts
21928
21930
  var DEFAULT_CEILING = 112;
21931
+ var CEILING_FLOOR = 16;
21929
21932
  var IDLE_MS = 1e4;
21930
21933
  var MARGIN = 16;
21934
+ var DECAY_MS = 6e4;
21935
+ var DECAY_STEP = 8;
21931
21936
  var WasmMemories = class {
21932
21937
  live = 0;
21933
- ceiling;
21938
+ learned;
21934
21939
  waiters = /* @__PURE__ */ new Set();
21940
+ base;
21935
21941
  idleMs;
21936
- constructor(ceiling, idleMs = IDLE_MS) {
21937
- this.ceiling = ceiling;
21942
+ now;
21943
+ constructor(ceiling, idleMs = IDLE_MS, now = Date.now) {
21944
+ this.base = ceiling;
21938
21945
  this.idleMs = idleMs;
21946
+ this.now = now;
21947
+ }
21948
+ ceiling() {
21949
+ const learned = this.learned;
21950
+ if (!learned) return this.base;
21951
+ const steps = Math.floor((this.now() - learned.at) / DECAY_MS);
21952
+ const raised = learned.ceiling + steps * DECAY_STEP;
21953
+ if (raised < (this.base ?? DEFAULT_CEILING)) return raised;
21954
+ this.learned = void 0;
21955
+ return this.base;
21939
21956
  }
21940
21957
  count() {
21941
- return { live: this.live, ceiling: this.ceiling ?? 0 };
21958
+ const ceiling = this.ceiling();
21959
+ const source = this.learned ? "learned" : ceiling === void 0 ? "none" : "default";
21960
+ return { live: this.live, ceiling: ceiling ?? 0, source };
21942
21961
  }
21943
21962
  ended() {
21944
21963
  this.live = Math.max(0, this.live - 1);
21945
21964
  this.progress();
21946
21965
  }
21947
21966
  learn() {
21948
- this.ceiling = Math.max(1, this.live - 1);
21967
+ const top = this.base ?? DEFAULT_CEILING;
21968
+ this.learned = {
21969
+ ceiling: Math.min(top, Math.max(CEILING_FLOOR, this.live - 1)),
21970
+ at: this.now()
21971
+ };
21949
21972
  }
21950
21973
  near() {
21951
- return this.ceiling !== void 0 && this.live + MARGIN >= this.ceiling;
21974
+ const ceiling = this.ceiling();
21975
+ return ceiling !== void 0 && this.live + MARGIN >= ceiling;
21952
21976
  }
21953
21977
  async admit() {
21954
- while (this.ceiling !== void 0 && this.live >= this.ceiling) {
21978
+ for (let ceiling = this.ceiling(); ceiling !== void 0 && this.live >= ceiling; ) {
21955
21979
  if (!await this.changed()) throw new SpawnError("EAGAIN");
21980
+ ceiling = this.ceiling();
21956
21981
  }
21957
21982
  this.live += 1;
21958
21983
  this.progress();
21959
21984
  }
21985
+ async refused() {
21986
+ const ceiling = this.ceiling();
21987
+ if (ceiling === void 0 || this.live >= ceiling) return;
21988
+ if (!await this.changed()) throw new SpawnError("EAGAIN");
21989
+ }
21960
21990
  progress() {
21961
21991
  const waiters = [...this.waiters];
21962
21992
  this.waiters.clear();
@@ -25217,6 +25247,10 @@ var Launcher = class {
25217
25247
  return handle;
25218
25248
  }
25219
25249
  await handle.exited;
25250
+ await this.memories.refused().catch(async (err) => {
25251
+ await fds.closeAll();
25252
+ throw err;
25253
+ });
25220
25254
  }
25221
25255
  }
25222
25256
  start(req) {
@@ -25282,7 +25316,8 @@ var Launcher = class {
25282
25316
  processes: this.list(this.credOf(pid)),
25283
25317
  load: this.loadAverage(),
25284
25318
  cpu: this.cpuTotal(),
25285
- wasm: this.memories.count()
25319
+ wasm: this.memories.count(),
25320
+ peers: Number(this.locks.shared?.() === true)
25286
25321
  }),
25287
25322
  sudo: (call, signal) => this.sudo(pid, call, signal),
25288
25323
  crontab: (call) => this.crontab(pid, call),