@ai-ecoverse/slicc-kernel 1.122.3 → 1.123.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.
package/dist/node.js CHANGED
@@ -3568,7 +3568,7 @@ var MemoryMeta = class {
3568
3568
  if (entry) this.entries.set(path, entry);
3569
3569
  else this.entries.delete(path);
3570
3570
  }
3571
- async move(from, to, root) {
3571
+ async move(from, to, root, left) {
3572
3572
  await this.remove([to]);
3573
3573
  const carried = this.entries.subtree(from).map((path) => this.entries.get(path));
3574
3574
  for (const entry of carried) this.entries.delete(entry.path);
@@ -3577,6 +3577,7 @@ var MemoryMeta = class {
3577
3577
  if (path !== to) this.entries.set(path, moved(entry, path));
3578
3578
  }
3579
3579
  this.entries.set(to, moved(root(carried.find((entry) => entry.path === from)), to));
3580
+ if (left) this.entries.set(from, left);
3580
3581
  }
3581
3582
  async remove(paths) {
3582
3583
  for (const path of paths) this.entries.deleteTree(path);
@@ -4228,6 +4229,14 @@ function sidecar(meta) {
4228
4229
  });
4229
4230
  return ops;
4230
4231
  }
4232
+ function occupied(entry) {
4233
+ if (!entry?.vacated) return entry ?? {};
4234
+ const { vacated: _, ...kept } = entry;
4235
+ return kept;
4236
+ }
4237
+ function vacatedAt(path) {
4238
+ return { path, ino: inodeOf(`${path}\0${crypto.randomUUID()}`), vacated: true };
4239
+ }
4231
4240
  function missing2(err) {
4232
4241
  const code = err?.code;
4233
4242
  return code === "ENOENT" || code === "ENOTDIR";
@@ -4458,7 +4467,7 @@ var OpfsFs = class {
4458
4467
  const kind = directory ? void 0 : owner?.socket ? "socket" : owner?.fifo ? "fifo" : void 0;
4459
4468
  const unique = kind === "fifo" ? { ino: inodeOf(`${path}\0${crypto.randomUUID()}`) } : {};
4460
4469
  const fields = kind ? { ...owned4, ...unique, [kind]: true } : owned4;
4461
- if (fields) await this.meta.update(path, (entry) => ({ ...entry, path, ...fields }));
4470
+ if (fields) await this.meta.update(path, (entry) => ({ ...occupied(entry), path, ...fields }));
4462
4471
  }
4463
4472
  guarded = [];
4464
4473
  protect(prefixes2, versions = false) {
@@ -5170,8 +5179,9 @@ var OpfsFs = class {
5170
5179
  await this.locked(physical, async () => {
5171
5180
  if (await this.handleExists(dir, name2)) throw fsError("EEXIST", path);
5172
5181
  const freshMeta = this.meta.fresh ? await this.meta.fresh([path]) : await this.meta.get([path]);
5173
- if (freshMeta[0]?.link !== void 0) throw fsError("EEXIST", path);
5174
- if (freshMeta[0] !== void 0) await this.meta.remove([path]);
5182
+ const found = freshMeta[0];
5183
+ if (found?.link !== void 0) throw fsError("EEXIST", path);
5184
+ if (found !== void 0 && !found.vacated) await this.meta.remove([path]);
5175
5185
  this.forget(physical);
5176
5186
  this.refuse(physical);
5177
5187
  await dir.getDirectoryHandle(name2, { create: true });
@@ -5191,8 +5201,9 @@ var OpfsFs = class {
5191
5201
  await this.locked(physical, async () => {
5192
5202
  if (await this.handleExists(dir, name2)) throw fsError("EEXIST", path);
5193
5203
  const freshMeta = this.meta.fresh ? await this.meta.fresh([path]) : await this.meta.get([path]);
5194
- if (freshMeta[0]?.link !== void 0) throw fsError("EEXIST", path);
5195
- if (freshMeta[0] !== void 0) await this.meta.remove([path]);
5204
+ const found = freshMeta[0];
5205
+ if (found?.link !== void 0) throw fsError("EEXIST", path);
5206
+ if (found !== void 0 && !found.vacated) await this.meta.remove([path]);
5196
5207
  this.forget(physical);
5197
5208
  this.refuse(physical);
5198
5209
  await dir.getFileHandle(name2, { create: true });
@@ -5296,14 +5307,15 @@ var OpfsFs = class {
5296
5307
  const moving = await this.movedOwner(source);
5297
5308
  const carry = (entry) => ({
5298
5309
  ino: inodeOf(source.path),
5299
- ...entry,
5310
+ ...occupied(entry),
5300
5311
  ...moving,
5301
5312
  path: destination,
5302
5313
  ctimeMs: now
5303
5314
  });
5315
+ const left = vacatedAt(source.path);
5304
5316
  if (source.link) {
5305
5317
  if (target?.handle) await this.rm(destination);
5306
- await this.meta.move(source.path, destination, carry);
5318
+ await this.meta.move(source.path, destination, carry, left);
5307
5319
  this.touch(Date.now(), parentOf4(source.path), parent.path);
5308
5320
  return;
5309
5321
  }
@@ -5318,9 +5330,12 @@ var OpfsFs = class {
5318
5330
  () => this.place(source.handle, dir, staging)
5319
5331
  );
5320
5332
  if (swap) await this.rm(destination, { recursive: true });
5321
- await this.meta.move(source.path, destination, carry);
5333
+ await this.meta.move(source.path, destination, carry, left);
5322
5334
  this.movePending(source.path, destination);
5323
- if (!moved2) await this.rm(source.path, { recursive: true });
5335
+ if (!moved2) {
5336
+ await this.rm(source.path, { recursive: true });
5337
+ await this.meta.update(source.path, () => left);
5338
+ }
5324
5339
  let copied = !moved2;
5325
5340
  if (swap) {
5326
5341
  const staged = await dir.getDirectoryHandle(staging);
@@ -5405,11 +5420,11 @@ var OpfsFs = class {
5405
5420
  const fields = await this.newFields(at, owner && { uid: owner.uid, gid: owner.gid }, false);
5406
5421
  await this.entering(
5407
5422
  at,
5408
- () => this.meta.update(at, () => ({
5423
+ () => this.meta.update(at, (entry) => ({
5409
5424
  path: at,
5410
5425
  link: target,
5411
5426
  dir: parent.path,
5412
- ino: inodeOf(at),
5427
+ ino: entry?.vacated && entry.ino !== void 0 ? entry.ino : inodeOf(at),
5413
5428
  mtimeMs: now,
5414
5429
  ctimeMs: now,
5415
5430
  ...fields
@@ -5477,7 +5492,10 @@ var OpfsFs = class {
5477
5492
  }
5478
5493
  async reconcile() {
5479
5494
  let removed = 0;
5480
- for (const entry of await this.meta.all()) {
5495
+ const entries = await this.meta.all();
5496
+ const carried = new Set(entries.filter((e) => !e.vacated).map((e) => e.ino));
5497
+ for (const entry of entries) {
5498
+ if (entry.vacated && carried.has(inodeOf(entry.path))) continue;
5481
5499
  const real = await this.real(entry.path);
5482
5500
  const stale = entry.link === void 0 ? !real : real || !await this.real(parentOf4(entry.path));
5483
5501
  if (!stale) continue;
@@ -6779,7 +6797,7 @@ function satisfies(version, range2) {
6779
6797
  }
6780
6798
 
6781
6799
  // src/version.ts
6782
- var KERNEL_VERSION = true ? "1.122.3" : "0.0.0-dev";
6800
+ var KERNEL_VERSION = true ? "1.123.1" : "0.0.0-dev";
6783
6801
  var OS_RELEASE = "6.0.0-slicc";
6784
6802
  function procVersion() {
6785
6803
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -12647,17 +12665,28 @@ var FALLBACK_MEMORY = 4 * KIB * KIB * KIB;
12647
12665
  var PID_FILES = ["cmdline", "comm", "stat", "statm", "status"];
12648
12666
  var SYSTEM_FILES = ["loadavg", "meminfo", "stat", "uptime", "version"];
12649
12667
  var SYS_TREE = {
12650
- kernel: { osrelease: `${OS_RELEASE}
12651
- `, ostype: "Linux\n" }
12668
+ kernel: {
12669
+ osrelease: `${OS_RELEASE}
12670
+ `,
12671
+ ostype: "Linux\n",
12672
+ slicc_wasm_memories: (listing) => `${listing.wasm?.live ?? 0} ${listing.wasm?.ceiling ?? 0}
12673
+ `
12674
+ }
12652
12675
  };
12676
+ function isSysFile(at) {
12677
+ return typeof at === "string" || typeof at === "function";
12678
+ }
12653
12679
  function sysEntry(parts2) {
12654
12680
  let at = SYS_TREE;
12655
12681
  for (const part of parts2) {
12656
- if (typeof at !== "object" || !Object.hasOwn(at, part)) return void 0;
12682
+ if (isSysFile(at) || !Object.hasOwn(at, part)) return void 0;
12657
12683
  at = at[part];
12658
12684
  }
12659
12685
  return at;
12660
12686
  }
12687
+ function sysText(file, listing) {
12688
+ return typeof file === "string" ? file : file(listing());
12689
+ }
12661
12690
  function commOf(info) {
12662
12691
  const name2 = info.argv[0] ?? "";
12663
12692
  return name2.slice(name2.lastIndexOf("/") + 1).slice(0, 15);
@@ -12893,7 +12922,9 @@ var ProcTree = class {
12893
12922
  }
12894
12923
  if (top === "sys") {
12895
12924
  const entry = sysEntry(parts2.slice(1));
12896
- if (typeof entry === "string") return { kind: "file", content: () => entry };
12925
+ if (typeof entry === "string" || typeof entry === "function") {
12926
+ return { kind: "file", content: () => sysText(entry, () => this.listing()) };
12927
+ }
12897
12928
  return entry && { kind: "dir", names: () => Object.keys(entry) };
12898
12929
  }
12899
12930
  if (top === "self") {
@@ -19192,6 +19223,7 @@ var WasmProcess = class {
19192
19223
  var WASM_PROCESS_INIT = "wasm-process-init";
19193
19224
  var WASM_PROCESS_EXIT = "wasm-process-exit";
19194
19225
  var WASM_PROCESS_ERROR = "wasm-process-error";
19226
+ var WASM_PROCESS_READY = "wasm-process-ready";
19195
19227
  var WASM_THREAD_SPAWN = "wasm-thread-spawn";
19196
19228
  var WASM_THREAD_INIT = "wasm-thread-init";
19197
19229
  var WASM_THREAD_EXIT = "wasm-thread-exit";
@@ -19199,6 +19231,8 @@ var WASM_MAX_THREADS = 256;
19199
19231
 
19200
19232
  // src/kernel/host.ts
19201
19233
  var CRASHED = 70;
19234
+ var NO_MEMORY = 126;
19235
+ var WASM_OOM = /Cannot allocate Wasm memory|WebAssembly\.Memory\(\): could not allocate memory/;
19202
19236
  var KILL_GRACE_MS = 2e3;
19203
19237
  var KILL_HARD_MS = 5e3;
19204
19238
  var descIds = /* @__PURE__ */ new WeakMap();
@@ -19464,7 +19498,22 @@ function threadInit(opts, program, sab, cred, thread, main) {
19464
19498
  function settleExit(exit, settle, code) {
19465
19499
  void exit.catch(() => void 0).then(() => settle(code & 255));
19466
19500
  }
19501
+ function readiness(abi) {
19502
+ const ready2 = Promise.withResolvers();
19503
+ if (abi === "js") ready2.resolve(true);
19504
+ return ready2;
19505
+ }
19506
+ function outOfMemory(opts, data) {
19507
+ if (data?.type !== WASM_PROCESS_ERROR || !WASM_OOM.test(String(data.message))) return false;
19508
+ if (!opts.onOom?.()) {
19509
+ opts.onError?.(
19510
+ `${opts.argv0}: cannot allocate memory for a new process (too many processes at once)`
19511
+ );
19512
+ }
19513
+ return true;
19514
+ }
19467
19515
  function spawnWasmProcess(opts) {
19516
+ const { promise: ready2, resolve: started } = readiness(opts.program.abi);
19468
19517
  const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
19469
19518
  const header4 = new Int32Array(sab, 0, SAB_HEADER_I32);
19470
19519
  const blocked2 = opts.fork?.wasi?.blocked ?? opts.blocked;
@@ -19517,6 +19566,7 @@ function spawnWasmProcess(opts) {
19517
19566
  const finish = (code, sig) => {
19518
19567
  if (done4) return;
19519
19568
  done4 = true;
19569
+ started(true);
19520
19570
  clocks.freeze();
19521
19571
  dying.clear();
19522
19572
  endedBy = sig ?? process2.execTermsig;
@@ -19534,7 +19584,12 @@ function spawnWasmProcess(opts) {
19534
19584
  queueMicrotask(() => finish(...dying.status(code)));
19535
19585
  };
19536
19586
  const handle = (data) => {
19537
- if (data?.type === WASM_PROCESS_EXIT) {
19587
+ if (data?.type === WASM_PROCESS_READY) {
19588
+ started(true);
19589
+ } else if (outOfMemory(opts, data)) {
19590
+ started(false);
19591
+ finish(NO_MEMORY);
19592
+ } else if (data?.type === WASM_PROCESS_EXIT) {
19538
19593
  finish(...dying.status(data.code));
19539
19594
  } else if (data?.type === WASM_PROCESS_ERROR) {
19540
19595
  if (!dying.ending) opts.onError?.(String(data.message));
@@ -19608,6 +19663,7 @@ function spawnWasmProcess(opts) {
19608
19663
  return {
19609
19664
  pid: opts.pid,
19610
19665
  exited,
19666
+ ready: ready2,
19611
19667
  kill,
19612
19668
  signal,
19613
19669
  termsig: () => endedBy,
@@ -21202,6 +21258,63 @@ var SettlingChildren = class {
21202
21258
  }
21203
21259
  };
21204
21260
 
21261
+ // src/kernel/wasm-memories.ts
21262
+ var DEFAULT_CEILING = 112;
21263
+ var IDLE_MS = 1e4;
21264
+ var MARGIN = 16;
21265
+ var WasmMemories = class {
21266
+ live = 0;
21267
+ ceiling;
21268
+ waiters = /* @__PURE__ */ new Set();
21269
+ idleMs;
21270
+ constructor(ceiling, idleMs = IDLE_MS) {
21271
+ this.ceiling = ceiling;
21272
+ this.idleMs = idleMs;
21273
+ }
21274
+ count() {
21275
+ return { live: this.live, ceiling: this.ceiling ?? 0 };
21276
+ }
21277
+ ended() {
21278
+ this.live = Math.max(0, this.live - 1);
21279
+ this.progress();
21280
+ }
21281
+ learn() {
21282
+ this.ceiling = Math.max(1, this.live - 1);
21283
+ }
21284
+ near() {
21285
+ return this.ceiling !== void 0 && this.live + MARGIN >= this.ceiling;
21286
+ }
21287
+ async admit() {
21288
+ while (this.ceiling !== void 0 && this.live >= this.ceiling) {
21289
+ if (!await this.changed()) throw new SpawnError("EAGAIN");
21290
+ }
21291
+ this.live += 1;
21292
+ this.progress();
21293
+ }
21294
+ progress() {
21295
+ const waiters = [...this.waiters];
21296
+ this.waiters.clear();
21297
+ for (const wake of waiters) wake();
21298
+ }
21299
+ changed() {
21300
+ return new Promise((resolve2) => {
21301
+ const wake = () => {
21302
+ clearTimeout(timer);
21303
+ resolve2(true);
21304
+ };
21305
+ const timer = setTimeout(() => {
21306
+ this.waiters.delete(wake);
21307
+ resolve2(false);
21308
+ }, this.idleMs);
21309
+ this.waiters.add(wake);
21310
+ });
21311
+ }
21312
+ };
21313
+ function defaultCeiling() {
21314
+ const node = globalThis.process?.versions?.node;
21315
+ return node === void 0 ? DEFAULT_CEILING : void 0;
21316
+ }
21317
+
21205
21318
  // src/mount/driver.ts
21206
21319
  function ownerOf2(req) {
21207
21320
  const owner = {
@@ -23467,6 +23580,9 @@ function withScriptEnv(target, command) {
23467
23580
  ]
23468
23581
  };
23469
23582
  }
23583
+ function memoriesOf(given) {
23584
+ return new WasmMemories(given?.ceiling ?? defaultCeiling(), given?.idleMs);
23585
+ }
23470
23586
  function childHandle(handle) {
23471
23587
  return {
23472
23588
  pid: handle.pid,
@@ -23538,6 +23654,7 @@ var Launcher = class {
23538
23654
  jobs = new JobTable();
23539
23655
  locks;
23540
23656
  fifos = new FifoTable();
23657
+ memories;
23541
23658
  sems = new SemTable();
23542
23659
  settling = new SettlingChildren((pid) => this.jobs.pgidOf(pid));
23543
23660
  ptys = new PtyTable(
@@ -23591,6 +23708,7 @@ var Launcher = class {
23591
23708
  terminals = 0;
23592
23709
  constructor(options) {
23593
23710
  this.usersMode = usersMode(options.users);
23711
+ this.memories = memoriesOf(options.wasmMemories);
23594
23712
  this.rootFs = options.fs;
23595
23713
  const peers = options.fs.peers?.();
23596
23714
  this.locks = kernelLocks(options.fs.rootName, peers);
@@ -24421,7 +24539,11 @@ var Launcher = class {
24421
24539
  }
24422
24540
  const done4 = this.heldUrl(program);
24423
24541
  try {
24424
- const handle = this.start({ ...req, cwd, program, argv0: target.argv0, args, env });
24542
+ const handle = await this.admitted(
24543
+ program.abi !== "js",
24544
+ req.fds,
24545
+ (fds, quietOom) => this.start({ ...req, fds, quietOom, cwd, program, argv0: target.argv0, args, env })
24546
+ );
24425
24547
  void handle.exited.finally(done4);
24426
24548
  return handle;
24427
24549
  } catch (err) {
@@ -24465,6 +24587,39 @@ var Launcher = class {
24465
24587
  if (req.tag !== void 0) this.tags.set(pid, req.tag);
24466
24588
  if (req.links !== void 0) this.links.set(pid, req.links);
24467
24589
  }
24590
+ async admitted(wasm, fds, start2) {
24591
+ if (!wasm) return start2(fds);
24592
+ for (; ; ) {
24593
+ await this.memories.admit().catch(async (err) => {
24594
+ await fds.closeAll();
24595
+ throw err;
24596
+ });
24597
+ const counted3 = (handle2) => {
24598
+ void handle2.exited.finally(() => this.memories.ended());
24599
+ return handle2;
24600
+ };
24601
+ if (!this.memories.near()) {
24602
+ try {
24603
+ return counted3(start2(fds));
24604
+ } catch (err) {
24605
+ this.memories.ended();
24606
+ throw err;
24607
+ }
24608
+ }
24609
+ const forked = fds.fork();
24610
+ const handle = await Promise.resolve().then(() => counted3(start2(forked, true))).catch(async (err) => {
24611
+ this.memories.ended();
24612
+ await forked.closeAll();
24613
+ throw err;
24614
+ });
24615
+ const fit = await (handle.ready ?? true);
24616
+ if (fit) {
24617
+ await fds.closeAll();
24618
+ return handle;
24619
+ }
24620
+ await handle.exited;
24621
+ }
24622
+ }
24468
24623
  start(req) {
24469
24624
  this.sampling();
24470
24625
  if (req.pgid !== void 0 && this.jobs.sessionOf(req.pgid) === void 0) {
@@ -24515,6 +24670,10 @@ var Launcher = class {
24515
24670
  ...this.prefixes.length > 0 && !stack.writer ? { readonlyAt: (path) => isProtected(this.prefixes, path) } : {},
24516
24671
  createWorker: this.createWorker,
24517
24672
  onError: req.report,
24673
+ onOom: () => {
24674
+ this.memories.learn();
24675
+ return req.quietOom === true;
24676
+ },
24518
24677
  spawner: this.spawner(pid, req.report),
24519
24678
  forker: this.forker(pid, req),
24520
24679
  kill: (target, sig, info) => this.kill(target, sig, this.credOf(pid), pid, info),
@@ -24523,7 +24682,8 @@ var Launcher = class {
24523
24682
  boot: this.boot,
24524
24683
  processes: this.list(this.credOf(pid)),
24525
24684
  load: this.loadAverage(),
24526
- cpu: this.cpuTotal()
24685
+ cpu: this.cpuTotal(),
24686
+ wasm: this.memories.count()
24527
24687
  }),
24528
24688
  sudo: (call, signal) => this.sudo(pid, call, signal),
24529
24689
  crontab: (call) => this.crontab(pid, call),
@@ -24860,9 +25020,10 @@ var Launcher = class {
24860
25020
  }
24861
25021
  forker(ppid, parent) {
24862
25022
  const { exec: _exec, pgid: _pgid, group: _group, pid: _pid, scrub: _scrub, ...image } = parent;
24863
- return async (state, fds) => childHandle(
24864
- this.start({
25023
+ return async (state, given) => {
25024
+ const fresh2 = (fds, quietOom) => this.start({
24865
25025
  ...image,
25026
+ quietOom,
24866
25027
  cwd: state.cwd ?? parent.cwd,
24867
25028
  fds,
24868
25029
  ppid,
@@ -24873,8 +25034,9 @@ var Launcher = class {
24873
25034
  cred: this.credOf(ppid),
24874
25035
  tag: this.tagOf(ppid),
24875
25036
  links: this.links.get(ppid)
24876
- })
24877
- );
25037
+ });
25038
+ return childHandle(await this.admitted(parent.program.abi !== "js", given, fresh2));
25039
+ };
24878
25040
  }
24879
25041
  keySignal(tty, fallback, sig, send) {
24880
25042
  const pgid = this.jobs.tcgetpgrp(tty, fallback);