@ai-ecoverse/slicc-kernel 1.30.0 → 1.30.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/README.md CHANGED
@@ -64,7 +64,7 @@ Starts `argv` as the session leader on a new terminal and resolves once it is ru
64
64
  | --- | --- |
65
65
  | `pid` | the session leader's pid |
66
66
  | `onData` | the output listener; output that arrives while it is `null` is kept and delivered when one is set |
67
- | `write(data)` | types a string or bytes into the terminal; with `ISIG` on, `^C`, `^Z` and `^\` signal the foreground process group |
67
+ | `write(data)` | types a string or bytes into the terminal; with `ISIG` on, `^C`, `^Z` and `^\` signal the foreground process group. A key typed while a child of that group is still setting up is held until the child has finished, then sent to the group in the foreground at that point. Setting up means the child's calls before its first other one: `setpgid`, `tcsetpgrp` and signal masks. The hold ends 250 ms after the child's first call at the latest. So `^Z` right after a command line stops the new job, as it does on Linux, where that setup takes microseconds rather than a worker start. |
68
68
  | `resize(cols, rows)` | sets the window size (`TIOCGWINSZ`) and sends `SIGWINCH` to the foreground process group |
69
69
  | `signal(name)` | sends a signal (`'SIGINT'`, `'SIGTSTP'`, `'SIGQUIT'`, `'SIGHUP'`, …) to the foreground process group, regardless of termios |
70
70
  | `exited` | resolves with the session leader's exit status (`128 + n` if killed by signal `n`) |
@@ -7876,7 +7876,7 @@ var WasmProcess = class {
7876
7876
  for (const listener of this.stateListeners) listener("continued", SIG.CONT);
7877
7877
  }
7878
7878
  async syscall(req) {
7879
- this.options.onSyscall?.();
7879
+ this.options.onSyscall?.(req);
7880
7880
  for (; ; ) {
7881
7881
  await this.resumed;
7882
7882
  const stops = this.stops;
@@ -8670,6 +8670,57 @@ var JobTable = class {
8670
8670
  }
8671
8671
  };
8672
8672
 
8673
+ // src/kernel/settling.ts
8674
+ var SETUP_OPS = /* @__PURE__ */ new Set([
8675
+ "proc-list",
8676
+ "proc-identity",
8677
+ "fd-info",
8678
+ "sig-mask",
8679
+ "proc-setpgid",
8680
+ "tty-pgrp-set"
8681
+ ]);
8682
+ var SETTLE_MS = 250;
8683
+ var KEY_SIGNALS = /* @__PURE__ */ new Set([2, 3, 20]);
8684
+ var SettlingChildren = class {
8685
+ children = /* @__PURE__ */ new Map();
8686
+ held = [];
8687
+ pgidOf;
8688
+ settleMs;
8689
+ constructor(pgidOf, settleMs = SETTLE_MS) {
8690
+ this.pgidOf = pgidOf;
8691
+ this.settleMs = settleMs;
8692
+ }
8693
+ started(pid, ppid) {
8694
+ this.children.set(pid, { ppid });
8695
+ }
8696
+ syscall(pid, op) {
8697
+ const child = this.children.get(pid);
8698
+ if (!child) return;
8699
+ if (!SETUP_OPS.has(op)) {
8700
+ this.settled(pid);
8701
+ return;
8702
+ }
8703
+ child.timer ??= setTimeout(() => this.settled(pid), this.settleMs);
8704
+ }
8705
+ settled(pid) {
8706
+ const child = this.children.get(pid);
8707
+ if (!child) return;
8708
+ clearTimeout(child.timer);
8709
+ this.children.delete(pid);
8710
+ const ready2 = this.held.filter((h) => !this.blocking(h.pgid));
8711
+ this.held = this.held.filter((h) => this.blocking(h.pgid));
8712
+ for (const h of ready2) h.send();
8713
+ }
8714
+ deliver(sig, pgid, send) {
8715
+ if (KEY_SIGNALS.has(sig) && this.blocking(pgid)) this.held.push({ pgid, send });
8716
+ else send();
8717
+ }
8718
+ blocking(pgid) {
8719
+ for (const { ppid } of this.children.values()) if (this.pgidOf(ppid) === pgid) return true;
8720
+ return false;
8721
+ }
8722
+ };
8723
+
8673
8724
  // src/mount/driver.ts
8674
8725
  function fsError2(code, message2 = code) {
8675
8726
  return Object.assign(new Error(message2), { code });
@@ -9930,7 +9981,14 @@ var Launcher = class {
9930
9981
  described = /* @__PURE__ */ new Map();
9931
9982
  jobs = new JobTable();
9932
9983
  locks = new LockTable();
9933
- ptys = new PtyTable((tty, sig) => this.jobs.signalOwnedForeground(tty, sig));
9984
+ settling = new SettlingChildren((pid) => this.jobs.pgidOf(pid));
9985
+ ptys = new PtyTable(
9986
+ (tty, sig) => this.settling.deliver(
9987
+ sig,
9988
+ this.jobs.tcgetpgrp(tty, 0),
9989
+ () => this.jobs.signalOwnedForeground(tty, sig)
9990
+ )
9991
+ );
9934
9992
  net = new LoopbackNet();
9935
9993
  cdp;
9936
9994
  ca;
@@ -10170,7 +10228,10 @@ var Launcher = class {
10170
10228
  await (asked ??= decided.then(count));
10171
10229
  return this.identityOf(pid);
10172
10230
  },
10173
- onSyscall: () => this.decide(pid),
10231
+ onSyscall: (call) => {
10232
+ this.decide(pid);
10233
+ this.settling.syscall(pid, call.op);
10234
+ },
10174
10235
  ...req.ignored ? { ignored: req.ignored } : {},
10175
10236
  program: req.program,
10176
10237
  argv0: req.argv0,
@@ -10203,6 +10264,7 @@ var Launcher = class {
10203
10264
  ...this.shownIds(req)
10204
10265
  });
10205
10266
  this.processes.set(pid, handle);
10267
+ if (req.ppid !== void 0) this.settling.started(pid, req.ppid);
10206
10268
  this.jobs.add(pid, req.ppid, (sig) => handle.signal(sig), terminal);
10207
10269
  if (req.exec && req.ppid !== void 0) this.jobs.exec(req.ppid, pid, true);
10208
10270
  if (req.pgid !== void 0) this.jobs.join(pid, req.pgid);
@@ -10213,6 +10275,7 @@ var Launcher = class {
10213
10275
  });
10214
10276
  void handle.exited.then(() => {
10215
10277
  this.processes.delete(pid);
10278
+ this.settling.settled(pid);
10216
10279
  if (req.ppid === void 0 || this.orphans.delete(pid)) this.forget(pid);
10217
10280
  else this.zombies.add(pid);
10218
10281
  });
@@ -10525,7 +10588,11 @@ var Launcher = class {
10525
10588
  let leader = 0;
10526
10589
  const tty = new KernelTty(
10527
10590
  { write: (bytes) => options.onData(bytes.slice()) },
10528
- (sig) => this.jobs.signalForeground(tty, leader, sig)
10591
+ (sig) => this.settling.deliver(
10592
+ sig,
10593
+ this.jobs.tcgetpgrp(tty, leader),
10594
+ () => this.jobs.signalForeground(tty, leader, sig)
10595
+ )
10529
10596
  );
10530
10597
  tty.name = `/dev/tty${++this.terminals}`;
10531
10598
  tty.setSize(options.cols ?? 80, options.rows ?? 24);