@ai-ecoverse/slicc-kernel 1.64.1 → 1.65.0

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.
@@ -6839,6 +6839,23 @@ var CONTINUED_STATUS = 65535;
6839
6839
  function waitStatus(code, termsig) {
6840
6840
  return termsig ? termsig & 127 : (code & 255) << 8;
6841
6841
  }
6842
+ function capturing(chunks, max = Number.POSITIVE_INFINITY, overflow) {
6843
+ let size = 0;
6844
+ let over = false;
6845
+ return (bytes) => {
6846
+ if (over) return;
6847
+ const room = max - size;
6848
+ if (bytes.length > room) {
6849
+ over = true;
6850
+ if (room > 0) chunks.push(bytes.slice(0, room));
6851
+ size = max;
6852
+ overflow?.();
6853
+ return;
6854
+ }
6855
+ chunks.push(bytes);
6856
+ size += bytes.length;
6857
+ };
6858
+ }
6842
6859
  function concat3(chunks) {
6843
6860
  const out = new Uint8Array(chunks.reduce((n, c) => n + c.length, 0));
6844
6861
  let offset = 0;
@@ -6872,15 +6889,15 @@ var ChildTable = class {
6872
6889
  const fds = new FdTable();
6873
6890
  const captured = /* @__PURE__ */ new Map();
6874
6891
  try {
6875
- for (const [n, slot] of stdio.entries()) fds.installAt(n, this.openSlot(slot, n, captured));
6876
- for (const slot of inherit2) {
6877
- if (slot.fd <= 2) continue;
6878
- if ("device" in slot) {
6879
- fds.installAt(slot.fd, deviceFile(slot.device, slot.access));
6892
+ for (const [n, slot2] of stdio.entries()) fds.installAt(n, this.openSlot(slot2, n, captured));
6893
+ for (const slot2 of inherit2) {
6894
+ if (slot2.fd <= 2) continue;
6895
+ if ("device" in slot2) {
6896
+ fds.installAt(slot2.fd, deviceFile(slot2.device, slot2.access));
6880
6897
  continue;
6881
6898
  }
6882
- fds.installAt(slot.fd, this.parentFds.get(slot.kernel).retain());
6883
- if (slot.flags !== void 0) fds.setStatusFlags(slot.fd, slot.flags);
6899
+ fds.installAt(slot2.fd, this.parentFds.get(slot2.kernel).retain());
6900
+ if (slot2.flags !== void 0) fds.setStatusFlags(slot2.fd, slot2.flags);
6884
6901
  }
6885
6902
  } catch (e) {
6886
6903
  await fds.closeAll();
@@ -6921,15 +6938,15 @@ var ChildTable = class {
6921
6938
  this.watchers.set(pid, listener);
6922
6939
  if (child.stoppedBy !== void 0) listener("stopped", child.stoppedBy);
6923
6940
  }
6924
- openSlot(slot, n, captured) {
6925
- if ("fd" in slot) return this.parentFds.get(slot.fd).retain();
6926
- if ("input" in slot) return bytesSource(slot.input);
6927
- if ("device" in slot) return deviceFile(slot.device, slot.access);
6928
- if ("dir" in slot) return heldFile({ dir: slot.dir });
6929
- if ("capture" in slot) {
6941
+ openSlot(slot2, n, captured) {
6942
+ if ("fd" in slot2) return this.parentFds.get(slot2.fd).retain();
6943
+ if ("input" in slot2) return bytesSource(slot2.input);
6944
+ if ("device" in slot2) return deviceFile(slot2.device, slot2.access);
6945
+ if ("dir" in slot2) return heldFile({ dir: slot2.dir });
6946
+ if ("capture" in slot2) {
6930
6947
  const chunks = [];
6931
6948
  captured.set(n, chunks);
6932
- return sinkFile((bytes) => chunks.push(bytes));
6949
+ return sinkFile(capturing(chunks, slot2.max, slot2.overflow));
6933
6950
  }
6934
6951
  return deviceFile("null");
6935
6952
  }
@@ -6996,11 +7013,11 @@ var ChildTable = class {
6996
7013
  pids() {
6997
7014
  return [...this.children.keys()];
6998
7015
  }
6999
- captured(pid, slot) {
7016
+ captured(pid, slot2) {
7000
7017
  const slots = this.leftovers.get(pid);
7001
- const chunks = slots?.get(slot);
7018
+ const chunks = slots?.get(slot2);
7002
7019
  if (!slots || !chunks) return new Uint8Array(0);
7003
- slots.delete(slot);
7020
+ slots.delete(slot2);
7004
7021
  if (slots.size === 0) this.leftovers.delete(pid);
7005
7022
  return concat3(chunks);
7006
7023
  }
@@ -8853,8 +8870,10 @@ var EARLY_WHOLE_FILE = 64 * 1024;
8853
8870
 
8854
8871
  // src/process/process-fds.ts
8855
8872
  var field2 = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
8873
+ var pinnedRoot;
8874
+ var rootKind = () => globalThis.navigator?.storage ? "opfs" : "memory";
8856
8875
  function mountTable(mounts = []) {
8857
- const root = globalThis.navigator?.storage ? "opfs" : "memory";
8876
+ const root = pinnedRoot ?? rootKind();
8858
8877
  const lines2 = [`${root} / ${root} rw 0 0`, "devfs /dev devfs rw 0 0", "proc /proc proc rw 0 0"];
8859
8878
  for (const m of mounts) {
8860
8879
  const options = Object.entries(m.options).map(([k, v]) => v === "" ? k : `${k}=${v}`);
@@ -9232,6 +9251,7 @@ var HOST_OPS = [
9232
9251
  "async-resolve",
9233
9252
  "async-hold",
9234
9253
  "async-cancel",
9254
+ "async-settle",
9235
9255
  "async-close"
9236
9256
  ];
9237
9257
  var json3 = (value) => ({ ok: true, kind: "json", json: value });
@@ -9263,12 +9283,16 @@ var LockTable = class {
9263
9283
  for (const path of [...this.held.keys()]) this.unlock(pid, path);
9264
9284
  }
9265
9285
  };
9286
+ var KEPT_OPS = /* @__PURE__ */ new Set(["fd-write"]);
9287
+ var unknownSettled = false;
9266
9288
  var AsyncOps = class {
9267
9289
  next = 1;
9268
9290
  results = /* @__PURE__ */ new Map();
9269
9291
  ready = [];
9270
9292
  running = /* @__PURE__ */ new Map();
9271
9293
  waiters = /* @__PURE__ */ new Set();
9294
+ taken = /* @__PURE__ */ new Map();
9295
+ kept = /* @__PURE__ */ new Set();
9272
9296
  closed = false;
9273
9297
  run;
9274
9298
  onReady;
@@ -9278,6 +9302,7 @@ var AsyncOps = class {
9278
9302
  }
9279
9303
  submit(req) {
9280
9304
  const id2 = this.hold();
9305
+ if (KEPT_OPS.has(req.op)) this.kept.add(id2);
9281
9306
  const running = new AbortController();
9282
9307
  this.running.set(id2, running);
9283
9308
  this.run(req, running.signal).then(
@@ -9301,9 +9326,26 @@ var AsyncOps = class {
9301
9326
  const result = this.results.get(id2);
9302
9327
  if (!result) throw new KernelError("EAGAIN");
9303
9328
  this.forget(id2);
9329
+ if (this.kept.delete(id2)) this.taken.set(id2, result);
9304
9330
  return result;
9305
9331
  }
9332
+ ack(ids) {
9333
+ for (const id2 of ids) this.taken.delete(id2);
9334
+ }
9335
+ async settle(ids) {
9336
+ const never = new AbortController().signal;
9337
+ while (ids.some((id2) => this.running.has(id2))) await this.sleep(void 0, never);
9338
+ return ids.map((id2) => {
9339
+ const result = this.results.get(id2) ?? this.taken.get(id2) ?? null;
9340
+ if (!result && !unknownSettled) {
9341
+ unknownSettled = true;
9342
+ console.warn(`async-settle: no result for op ${id2}; its write counts as made`);
9343
+ }
9344
+ return result;
9345
+ });
9346
+ }
9306
9347
  cancel(id2) {
9348
+ this.kept.delete(id2);
9307
9349
  this.running.get(id2)?.abort();
9308
9350
  this.forget(id2);
9309
9351
  }
@@ -9379,6 +9421,7 @@ async function hostSyscall(req, ctx) {
9379
9421
  return done2;
9380
9422
  case "async-submit":
9381
9423
  if (!ctx.valid(req.req)) throw new KernelError("EINVAL");
9424
+ if (req.ack) ctx.ops.ack(req.ack);
9382
9425
  return json3(ctx.ops.submit(req.req));
9383
9426
  case "async-wait":
9384
9427
  return json3(await ctx.ops.wait(req.timeoutMs, ctx.blocking));
@@ -9391,6 +9434,8 @@ async function hostSyscall(req, ctx) {
9391
9434
  case "async-cancel":
9392
9435
  ctx.ops.cancel(req.id);
9393
9436
  return done2;
9437
+ case "async-settle":
9438
+ return json3(await ctx.ops.settle(req.ids));
9394
9439
  case "async-close":
9395
9440
  ctx.ops.close();
9396
9441
  return done2;
@@ -9898,8 +9943,8 @@ var KernelTty = class {
9898
9943
  get canonical() {
9899
9944
  return (this.termios.c_lflag & ICANON) !== 0;
9900
9945
  }
9901
- cc(slot) {
9902
- return this.termios.c_cc[slot] ?? 0;
9946
+ cc(slot2) {
9947
+ return this.termios.c_cc[slot2] ?? 0;
9903
9948
  }
9904
9949
  key(input) {
9905
9950
  const { c_iflag, c_lflag } = this.termios;
@@ -10254,6 +10299,84 @@ function ptySyscall(req, ctx) {
10254
10299
  }
10255
10300
  }
10256
10301
 
10302
+ // src/kernel/run-child.ts
10303
+ var RUN_CAPTURE_CAP = 64 * 1024 * 1024;
10304
+ var RUN_MAX_BUFFER = 1024 * 1024;
10305
+ function capLimit(maxBuffer) {
10306
+ const asked = maxBuffer === void 0 ? RUN_MAX_BUFFER : maxBuffer;
10307
+ return Math.max(0, Math.min(asked, RUN_CAPTURE_CAP));
10308
+ }
10309
+ function slot(how, n, extra) {
10310
+ if (how === "inherit") return { fd: n };
10311
+ if (how === "ignore") return { none: true };
10312
+ return extra;
10313
+ }
10314
+ function frame2(outcome, out, err) {
10315
+ const head = new TextEncoder().encode(JSON.stringify(outcome));
10316
+ const bytes = new Uint8Array(4 + head.length + out.length + err.length);
10317
+ new DataView(bytes.buffer).setUint32(0, head.length, true);
10318
+ bytes.set(head, 4);
10319
+ bytes.set(out, 4 + head.length);
10320
+ bytes.set(err, 4 + head.length + out.length);
10321
+ return bytes;
10322
+ }
10323
+ async function reaped(deps, pid) {
10324
+ for (; ; ) {
10325
+ try {
10326
+ return (await deps.children.wait(pid, false, deps.interrupt()))[1];
10327
+ } catch (e) {
10328
+ if (!(e instanceof KernelError && e.code === "EINTR") || deps.dying()) throw e;
10329
+ }
10330
+ }
10331
+ }
10332
+ async function runChild(req, deps) {
10333
+ const max = capLimit(req.maxBuffer);
10334
+ let failure2;
10335
+ let pid = 0;
10336
+ const kill = () => void Promise.allSettled([deps.kill(pid, req.killSignal)]);
10337
+ const stop = (code) => {
10338
+ if (failure2 !== void 0) return;
10339
+ failure2 = code;
10340
+ if (pid !== 0) kill();
10341
+ };
10342
+ const capture = () => ({ capture: true, max, overflow: () => stop("ENOBUFS") });
10343
+ const stdio = [
10344
+ slot(req.stdin, 0, { input: req.input ?? new Uint8Array(0) }),
10345
+ slot(req.stdout, 1, capture()),
10346
+ slot(req.stderr, 2, capture())
10347
+ ];
10348
+ try {
10349
+ pid = await deps.children.spawn(
10350
+ { file: req.file, argv: req.argv, env: req.env, cwd: req.cwd },
10351
+ stdio
10352
+ );
10353
+ } catch (e) {
10354
+ if (!(e instanceof SpawnError)) throw e;
10355
+ const outcome2 = { pid: 0, status: null, error: { code: e.code }, out: 0, err: 0 };
10356
+ return frame2(outcome2, new Uint8Array(0), new Uint8Array(0));
10357
+ }
10358
+ if (failure2 !== void 0) kill();
10359
+ const timer = req.timeoutMs !== void 0 && req.timeoutMs > 0 ? setTimeout(() => stop("ETIMEDOUT"), req.timeoutMs) : void 0;
10360
+ let status;
10361
+ try {
10362
+ status = await reaped(deps, pid);
10363
+ } finally {
10364
+ clearTimeout(timer);
10365
+ }
10366
+ const out = deps.children.captured(pid, 1);
10367
+ const err = deps.children.captured(pid, 2);
10368
+ const termsig = status & 127;
10369
+ const outcome = {
10370
+ pid,
10371
+ status: termsig ? null : status >> 8 & 255,
10372
+ ...termsig ? { signal: termsig } : {},
10373
+ ...failure2 !== void 0 ? { error: { code: failure2 } } : {},
10374
+ out: out.length,
10375
+ err: err.length
10376
+ };
10377
+ return frame2(outcome, out, err);
10378
+ }
10379
+
10257
10380
  // src/kernel/select.ts
10258
10381
  function ready(fds, read, write) {
10259
10382
  const hangup = /* @__PURE__ */ new Set();
@@ -11050,6 +11173,8 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
11050
11173
  "proc-spawn",
11051
11174
  "proc-wait",
11052
11175
  "proc-captured",
11176
+ "proc-run",
11177
+ "proc-exit",
11053
11178
  "proc-fork",
11054
11179
  "proc-kill",
11055
11180
  "thread-kill",
@@ -11170,6 +11295,14 @@ var WasmProcess = class {
11170
11295
  else this.adoptExec(pid);
11171
11296
  return pid;
11172
11297
  }
11298
+ run(req) {
11299
+ return runChild(req, {
11300
+ children: this.children,
11301
+ kill: (pid, sig) => this.options.kill?.(pid, sig),
11302
+ interrupt: () => this.interrupt.signal,
11303
+ dying: () => this.dying
11304
+ });
11305
+ }
11173
11306
  adoptExec(pid) {
11174
11307
  this.execChild = pid;
11175
11308
  this.children.watch(pid, (state, sig) => state === "stopped" ? this.stop(sig) : this.cont());
@@ -11718,6 +11851,12 @@ var WasmProcess = class {
11718
11851
  return { ok: true, kind: "json", json: await this.spawn(req) };
11719
11852
  case "proc-wait":
11720
11853
  return { ok: true, kind: "json", json: await this.procWait(req, cancelled) };
11854
+ case "proc-run":
11855
+ return { ok: true, kind: "bytes", bytes: await this.run(req) };
11856
+ case "proc-exit":
11857
+ if (!this.options.exitNow) throw new KernelError("ENOSYS");
11858
+ this.options.exitNow(req.status & 255);
11859
+ return DYING;
11721
11860
  case "proc-identity":
11722
11861
  return { ok: true, kind: "json", json: await this.options.identity?.() ?? null };
11723
11862
  case "proc-exec": {
@@ -12124,6 +12263,7 @@ function processOptions(opts, header3, hooks, created3) {
12124
12263
  hasPending: () => Atomics.load(header3, SAB_I_SIGNALS) !== 0 || Atomics.load(header3, SAB_I_TIMERS) !== 0,
12125
12264
  raise: hooks.raise,
12126
12265
  threadKill: hooks.threadKill,
12266
+ ...hooks.exitNow ? { exitNow: hooks.exitNow } : {},
12127
12267
  ...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header3, SAB_I_SIGNALS) } : {}
12128
12268
  };
12129
12269
  }
@@ -12140,7 +12280,8 @@ function spawnWasmProcess(opts) {
12140
12280
  header3,
12141
12281
  {
12142
12282
  raise: (sig) => signal(sig),
12143
- threadKill: (tid, sig) => killThread(threadSignals.get(tid), process.signalMasks().caught, sig)
12283
+ threadKill: (tid, sig) => killThread(threadSignals.get(tid), process.signalMasks().caught, sig),
12284
+ ...opts.program.abi === "js" ? { exitNow: (code) => exitNow(code) } : {}
12144
12285
  },
12145
12286
  created3
12146
12287
  )
@@ -12181,12 +12322,15 @@ function spawnWasmProcess(opts) {
12181
12322
  () => settle3(code)
12182
12323
  );
12183
12324
  };
12325
+ const exitNow = (code) => {
12326
+ queueMicrotask(() => finish(...dying.status(code)));
12327
+ };
12184
12328
  const handle = (data) => {
12185
12329
  if (data?.type === WASM_PROCESS_EXIT) {
12186
12330
  finish(...dying.status(data.code));
12187
12331
  } else if (data?.type === WASM_PROCESS_ERROR) {
12188
12332
  if (!dying.ending) opts.onError?.(String(data.message));
12189
- finish(...dying.status(CRASHED));
12333
+ finish(...dying.status(data.code));
12190
12334
  } else if (data?.type === WASM_THREAD_SPAWN && data.thread) {
12191
12335
  spawnThread(data.thread);
12192
12336
  }
@@ -12916,15 +13060,15 @@ function granted(handle) {
12916
13060
  );
12917
13061
  }
12918
13062
  function removableMedium(onLost, open = (handle) => new OpfsFs(handle)) {
12919
- const slot = mediumSlot(
13063
+ const slot2 = mediumSlot(
12920
13064
  async (err, handle) => denied(err) && !await granted(handle),
12921
13065
  onLost
12922
13066
  );
12923
13067
  return {
12924
- handlers: slot.handlers,
12925
- present: slot.present,
12926
- insert: (handle) => slot.insert(handle, kernelFsHandlers(open(handle))),
12927
- eject: slot.eject
13068
+ handlers: slot2.handlers,
13069
+ present: slot2.present,
13070
+ insert: (handle) => slot2.insert(handle, kernelFsHandlers(open(handle))),
13071
+ eject: slot2.eject
12928
13072
  };
12929
13073
  }
12930
13074
 
@@ -13708,7 +13852,7 @@ function grantConnect(hook, fetch2, liveness = {}) {
13708
13852
  async function openHostfs(spec, connect, timing = {}) {
13709
13853
  const readonly2 = spec.options?.ro !== void 0;
13710
13854
  const { port1, port2 } = new MessageChannel();
13711
- const slot = mediumSlot(
13855
+ const slot2 = mediumSlot(
13712
13856
  async (err) => unreachable(err),
13713
13857
  () => watching.kick()
13714
13858
  );
@@ -13721,7 +13865,7 @@ async function openHostfs(spec, connect, timing = {}) {
13721
13865
  });
13722
13866
  const served = serveFilesystem(
13723
13867
  port2,
13724
- { ...slot.handlers, mount: ranged2 },
13868
+ { ...slot2.handlers, mount: ranged2 },
13725
13869
  {
13726
13870
  symlinks: true,
13727
13871
  chmod: true,
@@ -13735,12 +13879,12 @@ async function openHostfs(spec, connect, timing = {}) {
13735
13879
  connect: () => connect(spec.source, { readonly: readonly2 }),
13736
13880
  up(client) {
13737
13881
  active = timed(client, timing.callMs ?? HOSTFS_CALL_MS);
13738
- slot.insert(client, handlers);
13882
+ slot2.insert(client, handlers);
13739
13883
  served.invalidate(true);
13740
13884
  },
13741
13885
  event: (event) => served.invalidate(invalidation(event)),
13742
13886
  down() {
13743
- slot.eject();
13887
+ slot2.eject();
13744
13888
  served.invalidate(true);
13745
13889
  },
13746
13890
  ...timing
@@ -13750,7 +13894,7 @@ async function openHostfs(spec, connect, timing = {}) {
13750
13894
  await watching.ready;
13751
13895
  return {
13752
13896
  port: port1,
13753
- present: slot.present,
13897
+ present: slot2.present,
13754
13898
  dispose() {
13755
13899
  stop.abort();
13756
13900
  port1.close();
@@ -15044,16 +15188,16 @@ var Launcher = class {
15044
15188
  }
15045
15189
  async insert(target, handle, source) {
15046
15190
  const at = normalizePath(target);
15047
- const slot = this.removable.get(at);
15048
- if (!slot) throw fsError("EINVAL", `${at} is not a removable mount`);
15049
- if (source !== void 0 && source !== `fsa:${slot.id}`) {
15191
+ const slot2 = this.removable.get(at);
15192
+ if (!slot2) throw fsError("EINVAL", `${at} is not a removable mount`);
15193
+ if (source !== void 0 && source !== `fsa:${slot2.id}`) {
15050
15194
  throw fsError("EINVAL", `${at} is no longer the drive ${source}`);
15051
15195
  }
15052
15196
  if (!await granted(handle)) throw fsError("EACCES", `${at}: no permission for this folder`);
15053
- this.inserted.set(slot.id, handle);
15054
- await this.media.put(slot.id, handle);
15055
- slot.medium.insert(handle);
15056
- slot.served.invalidate(true);
15197
+ this.inserted.set(slot2.id, handle);
15198
+ await this.media.put(slot2.id, handle);
15199
+ slot2.medium.insert(handle);
15200
+ slot2.served.invalidate(true);
15057
15201
  void this.unlinked.sweep(at);
15058
15202
  }
15059
15203
  umount(target, detach = false) {