@ai-ecoverse/slicc-kernel 1.103.4 → 1.106.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.
Files changed (38) hide show
  1. package/README.md +57 -16
  2. package/dist/driver-worker.js +36 -1
  3. package/dist/driver-worker.js.map +2 -2
  4. package/dist/index.js +89 -5
  5. package/dist/index.js.map +2 -2
  6. package/dist/kernel-worker.js +798 -295
  7. package/dist/kernel-worker.js.map +4 -4
  8. package/dist/meta.js.map +2 -2
  9. package/dist/node-driver-worker.js +36 -1
  10. package/dist/node-driver-worker.js.map +2 -2
  11. package/dist/node-process-worker.js +489 -234
  12. package/dist/node-process-worker.js.map +4 -4
  13. package/dist/node.js +846 -315
  14. package/dist/node.js.map +4 -4
  15. package/dist/process-worker.js +426 -171
  16. package/dist/process-worker.js.map +4 -4
  17. package/dist/types/commands.d.ts +6 -1
  18. package/dist/types/fs/command-stat.d.ts +3 -0
  19. package/dist/types/fs/commands.d.ts +7 -1
  20. package/dist/types/fs/engines.d.ts +5 -0
  21. package/dist/types/fs/types.d.ts +1 -0
  22. package/dist/types/kernel/host.d.ts +1 -0
  23. package/dist/types/kernel/net/http-syscalls.d.ts +10 -0
  24. package/dist/types/kernel/net/http1.d.ts +1 -0
  25. package/dist/types/kernel/net/remote-transport.d.ts +18 -0
  26. package/dist/types/kernel/net/transport.d.ts +2 -0
  27. package/dist/types/kernel/process.d.ts +8 -0
  28. package/dist/types/launcher.d.ts +4 -0
  29. package/dist/types/process/js/js-kernel.d.ts +2 -1
  30. package/dist/types/process/process-signals.d.ts +3 -0
  31. package/dist/types/process/wasi/wasi-cred.d.ts +11 -0
  32. package/dist/types/process/wasi/wasi-files.d.ts +1 -0
  33. package/dist/types/process/wasi/wasi-host.d.ts +9 -0
  34. package/dist/types/process/wasi/wasi-sigmask.d.ts +7 -1
  35. package/dist/types/process/wasi/wasix-epoll.d.ts +3 -0
  36. package/dist/types/refused-command.d.ts +4 -0
  37. package/dist/types/transport.d.ts +1 -0
  38. package/package.json +12 -12
@@ -887,7 +887,7 @@ function pinnedIo(bridge, handle, rewriting) {
887
887
  } : {}
888
888
  };
889
889
  }
890
- var WasiError, FileBuffer, LocalFile, MAX_LINKS, MISS_TTL_MS, FS_GEN, RING, RING_SIZE, SLOT, SHARED_IDS_BYTES, StatCache;
890
+ var WasiError, FileBuffer, LocalFile, MAX_LINKS, MISS_TTL_MS, FS_GEN, CRED_GEN, RING, RING_SIZE, SLOT, SHARED_IDS_BYTES, StatCache;
891
891
  var init_wasi_files = __esm({
892
892
  "src/process/wasi/wasi-files.ts"() {
893
893
  "use strict";
@@ -1109,6 +1109,7 @@ var init_wasi_files = __esm({
1109
1109
  MAX_LINKS = 40;
1110
1110
  MISS_TTL_MS = 20;
1111
1111
  FS_GEN = 4;
1112
+ CRED_GEN = 5;
1112
1113
  RING = 8;
1113
1114
  RING_SIZE = 64;
1114
1115
  SLOT = 3;
@@ -1598,6 +1599,69 @@ var init_cred = __esm({
1598
1599
  }
1599
1600
  });
1600
1601
 
1602
+ // src/kernel/signals.ts
1603
+ function defaultAction(sig) {
1604
+ if (sig === SIG.CONT) return "continue";
1605
+ if (STOPPING.has(sig)) return "stop";
1606
+ return IGNORED_BY_DEFAULT.has(sig) ? "ignore" : "terminate";
1607
+ }
1608
+ function sigbit(sig) {
1609
+ return 1 << sig;
1610
+ }
1611
+ function signalsIn(mask) {
1612
+ const out = [];
1613
+ for (let sig = 1; sig <= 31; sig++) if (mask & sigbit(sig)) out.push(sig);
1614
+ return out;
1615
+ }
1616
+ var SIG, IGNORED_BY_DEFAULT, STOPPING, SIGNAL_BY_NAME;
1617
+ var init_signals = __esm({
1618
+ "src/kernel/signals.ts"() {
1619
+ "use strict";
1620
+ SIG = {
1621
+ HUP: 1,
1622
+ INT: 2,
1623
+ QUIT: 3,
1624
+ ILL: 4,
1625
+ TRAP: 5,
1626
+ ABRT: 6,
1627
+ BUS: 7,
1628
+ FPE: 8,
1629
+ KILL: 9,
1630
+ USR1: 10,
1631
+ SEGV: 11,
1632
+ USR2: 12,
1633
+ PIPE: 13,
1634
+ ALRM: 14,
1635
+ TERM: 15,
1636
+ STKFLT: 16,
1637
+ CHLD: 17,
1638
+ CONT: 18,
1639
+ STOP: 19,
1640
+ TSTP: 20,
1641
+ TTIN: 21,
1642
+ TTOU: 22,
1643
+ URG: 23,
1644
+ XCPU: 24,
1645
+ XFSZ: 25,
1646
+ VTALRM: 26,
1647
+ PROF: 27,
1648
+ WINCH: 28,
1649
+ POLL: 29,
1650
+ PWR: 30,
1651
+ SYS: 31
1652
+ };
1653
+ IGNORED_BY_DEFAULT = /* @__PURE__ */ new Set([SIG.CHLD, SIG.URG, SIG.WINCH]);
1654
+ STOPPING = /* @__PURE__ */ new Set([SIG.STOP, SIG.TSTP, SIG.TTIN, SIG.TTOU]);
1655
+ SIGNAL_BY_NAME = {
1656
+ SIGINT: SIG.INT,
1657
+ SIGTERM: SIG.TERM,
1658
+ SIGKILL: SIG.KILL,
1659
+ SIGSTOP: SIG.STOP,
1660
+ SIGCONT: SIG.CONT
1661
+ };
1662
+ }
1663
+ });
1664
+
1601
1665
  // src/process/wasi/slicc-lock.ts
1602
1666
  function kindOf(type) {
1603
1667
  if (type === F_RDLCK) return "read";
@@ -1712,6 +1776,48 @@ var init_slicc_sem = __esm({
1712
1776
  }
1713
1777
  });
1714
1778
 
1779
+ // src/process/wasi/wasi-cred.ts
1780
+ var CredCache;
1781
+ var init_wasi_cred = __esm({
1782
+ "src/process/wasi/wasi-cred.ts"() {
1783
+ "use strict";
1784
+ init_wasi_files();
1785
+ CredCache = class {
1786
+ cred;
1787
+ stamp = 0;
1788
+ fetch;
1789
+ shared;
1790
+ constructor(fetch, shared) {
1791
+ this.fetch = fetch;
1792
+ this.shared = shared;
1793
+ }
1794
+ gen() {
1795
+ return this.shared ? Atomics.load(this.shared, CRED_GEN) : 0;
1796
+ }
1797
+ get() {
1798
+ const gen = this.gen();
1799
+ if (this.cred === void 0 || this.stamp !== gen) {
1800
+ this.cred = this.fetch();
1801
+ this.stamp = gen;
1802
+ }
1803
+ return this.cred;
1804
+ }
1805
+ change(apply2) {
1806
+ const seen = this.gen();
1807
+ const cred = apply2();
1808
+ if (!this.shared) {
1809
+ this.cred = cred;
1810
+ return cred;
1811
+ }
1812
+ const was = Atomics.add(this.shared, CRED_GEN, 1);
1813
+ this.cred = was === seen ? cred : void 0;
1814
+ this.stamp = was + 1;
1815
+ return cred;
1816
+ }
1817
+ };
1818
+ }
1819
+ });
1820
+
1715
1821
  // src/kernel/pipe.ts
1716
1822
  var PIPE_CAPACITY;
1717
1823
  var init_pipe = __esm({
@@ -2800,6 +2906,92 @@ var init_wasi_termios = __esm({
2800
2906
  }
2801
2907
  });
2802
2908
 
2909
+ // src/process/wasi/wasix-epoll.ts
2910
+ function timeoutMs(ns) {
2911
+ const value2 = BigInt.asUintN(64, ns);
2912
+ if (value2 === FOREVER) return -1;
2913
+ const ms = (value2 + NS_PER_MS2 - 1n) / NS_PER_MS2;
2914
+ return ms > BigInt(MAX_TIMEOUT_MS) ? -1 : Number(ms);
2915
+ }
2916
+ function wasixEpollImports(host) {
2917
+ const { mem, fds, o } = host;
2918
+ const call2 = (req) => o.kernel.call(req);
2919
+ const kernelFd = (fd, refusal2) => {
2920
+ const e = fds.find(fd);
2921
+ if (!e) throw new WasiError("EBADF");
2922
+ if (e.type !== "kernel") throw new WasiError(refusal2);
2923
+ };
2924
+ const writeEvents2 = (ptr, events) => {
2925
+ const view = mem.view();
2926
+ events.forEach((ev, i) => {
2927
+ const at = ptr + i * EVENT_SIZE;
2928
+ mem.bytes(at, EVENT_SIZE).fill(0);
2929
+ view.setUint32(at, ev.events, true);
2930
+ mem.bytes(at + DATA_OFFSET, DATA_SIZE).set(ev.data);
2931
+ });
2932
+ };
2933
+ return {
2934
+ epoll_create: (out) => {
2935
+ const fd = call2({ op: "epoll-create" });
2936
+ fds.adopt(fd, "stream", false);
2937
+ mem.view().setUint32(out, fd, true);
2938
+ },
2939
+ epoll_ctl: (epfd, op, fd, event) => {
2940
+ const how = (host.strictEpoll ? WASIX_OPS : DUAL_OPS)[op];
2941
+ if (!how) throw new WasiError("EINVAL");
2942
+ kernelFd(epfd, "EINVAL");
2943
+ kernelFd(fd, "EPERM");
2944
+ if (how !== "del" && event === 0) throw new WasiError("EINVAL");
2945
+ const events = event === 0 ? 0 : mem.view().getUint32(event, true);
2946
+ const data = event === 0 ? [] : [...mem.bytes(event + DATA_OFFSET, DATA_SIZE)];
2947
+ call2({ op: "epoll-ctl", epfd, how, fd, events, data });
2948
+ },
2949
+ epoll_wait: (epfd, ptr, maxevents, timeout, out) => {
2950
+ mem.view().setUint32(out, 0, true);
2951
+ if ((maxevents | 0) <= 0) throw new WasiError("EINVAL");
2952
+ kernelFd(epfd, "EINVAL");
2953
+ const max = Math.min(maxevents | 0, MAX_EVENTS);
2954
+ const ms = host.entered ? 0 : timeoutMs(timeout);
2955
+ const events = call2({ op: "epoll-wait", epfd, max, timeoutMs: ms });
2956
+ if (host.entered && events.length === 0 && timeoutMs(timeout) !== 0) return E.INTR;
2957
+ writeEvents2(ptr, events);
2958
+ mem.view().setUint32(out, events.length, true);
2959
+ return E.SUCCESS;
2960
+ },
2961
+ fd_event: (initial, flags, out) => {
2962
+ const value2 = BigInt.asUintN(64, initial);
2963
+ if (value2 > EVENTFD_MAX) throw new WasiError("EINVAL");
2964
+ const fd = call2({
2965
+ op: "eventfd-open",
2966
+ initial: value2.toString(),
2967
+ semaphore: (flags & EVENTFD_SEMAPHORE) !== 0
2968
+ });
2969
+ fds.adopt(fd, "stream", (flags & EVENTFD_NONBLOCK) !== 0);
2970
+ mem.view().setUint32(out, fd, true);
2971
+ }
2972
+ };
2973
+ }
2974
+ var EVENT_SIZE, DATA_OFFSET, DATA_SIZE, MAX_EVENTS, FOREVER, MAX_TIMEOUT_MS, NS_PER_MS2, EVENTFD_SEMAPHORE, EVENTFD_NONBLOCK, EVENTFD_MAX, WASIX_OPS, DUAL_OPS;
2975
+ var init_wasix_epoll = __esm({
2976
+ "src/process/wasi/wasix-epoll.ts"() {
2977
+ "use strict";
2978
+ init_wasi_abi();
2979
+ init_wasi_files();
2980
+ EVENT_SIZE = 32;
2981
+ DATA_OFFSET = 8;
2982
+ DATA_SIZE = 24;
2983
+ MAX_EVENTS = 4096;
2984
+ FOREVER = 0xffffffffffffffffn;
2985
+ MAX_TIMEOUT_MS = 2147483647;
2986
+ NS_PER_MS2 = 1000000n;
2987
+ EVENTFD_SEMAPHORE = 1;
2988
+ EVENTFD_NONBLOCK = 4;
2989
+ EVENTFD_MAX = 0xfffffffffffffffen;
2990
+ WASIX_OPS = ["add", "mod", "del"];
2991
+ DUAL_OPS = ["add", "set", "del", "mod"];
2992
+ }
2993
+ });
2994
+
2803
2995
  // src/kernel/net/datagram-wire.ts
2804
2996
  function decodeReceived(raw) {
2805
2997
  const view = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
@@ -3232,7 +3424,7 @@ function filestatOf(path, s) {
3232
3424
  size: BigInt(s.size),
3233
3425
  ino: s.ino !== void 0 ? BigInt(s.ino) : pathInode(path),
3234
3426
  ...s.nlink !== void 0 ? { nlink: BigInt(s.nlink) } : {},
3235
- mtimeNs: BigInt(Math.round(s.mtimeMs ?? 0)) * NS_PER_MS2
3427
+ mtimeNs: BigInt(Math.round(s.mtimeMs ?? 0)) * NS_PER_MS3
3236
3428
  };
3237
3429
  }
3238
3430
  function kernelFiletype(kind) {
@@ -3282,7 +3474,7 @@ function wrap(table) {
3282
3474
  }
3283
3475
  return out;
3284
3476
  }
3285
- var WasiExit, IDS, NS_PER_MS2, AT_SYMLINK_NOFOLLOW, AT_EACCESS, ROOT_IDS, GONE, S_IFIFO, DEFAULT_UMASK, MONOTONIC_BASE, MAX_READ, SIGPIPE_EXIT, SIG_IGN, SEALED_MODE, WasiHost;
3477
+ var WasiExit, IDS, NS_PER_MS3, AT_SYMLINK_NOFOLLOW, AT_EACCESS, ROOT_IDS, GONE, S_IFIFO, DEFAULT_UMASK, MONOTONIC_BASE, MAX_READ, SIGPIPE_EXIT, SIG_IGN, SEALED_MODE, WasiHost;
3286
3478
  var init_wasi_host = __esm({
3287
3479
  "src/process/wasi/wasi-host.ts"() {
3288
3480
  "use strict";
@@ -3290,14 +3482,17 @@ var init_wasi_host = __esm({
3290
3482
  init_physical_path();
3291
3483
  init_cpu_clock();
3292
3484
  init_cred();
3485
+ init_signals();
3293
3486
  init_slicc_lock();
3294
3487
  init_slicc_sem();
3295
3488
  init_wasi_abi();
3489
+ init_wasi_cred();
3296
3490
  init_wasi_fds();
3297
3491
  init_wasi_files();
3298
3492
  init_wasi_memory();
3299
3493
  init_wasi_poll();
3300
3494
  init_wasi_termios();
3495
+ init_wasix_epoll();
3301
3496
  init_wasix_sockets();
3302
3497
  WasiExit = class extends Error {
3303
3498
  code;
@@ -3307,26 +3502,30 @@ var init_wasi_host = __esm({
3307
3502
  }
3308
3503
  };
3309
3504
  IDS = ["ruid", "euid", "suid", "rgid", "egid", "sgid"];
3310
- NS_PER_MS2 = 1000000n;
3505
+ NS_PER_MS3 = 1000000n;
3311
3506
  AT_SYMLINK_NOFOLLOW = 1;
3312
3507
  AT_EACCESS = 2;
3313
3508
  ROOT_IDS = Object.freeze({ uid: 0, gid: 0 });
3314
3509
  GONE = /* @__PURE__ */ new Set(["ENOENT", "ENOTDIR"]);
3315
3510
  S_IFIFO = 4096;
3316
3511
  DEFAULT_UMASK = 18;
3317
- MONOTONIC_BASE = BigInt(Math.round(performance.timeOrigin)) * NS_PER_MS2;
3512
+ MONOTONIC_BASE = BigInt(Math.round(performance.timeOrigin)) * NS_PER_MS3;
3318
3513
  MAX_READ = 1024 * 1024;
3319
- SIGPIPE_EXIT = 141;
3514
+ SIGPIPE_EXIT = 128 + SIG.PIPE;
3320
3515
  SIG_IGN = 1;
3321
3516
  SEALED_MODE = 8630;
3322
3517
  WasiHost = class {
3323
3518
  mem = new WasiMemory();
3324
3519
  fds;
3520
+ creds;
3325
3521
  started = performance.now();
3326
3522
  cache;
3327
3523
  startCwd;
3328
3524
  interruptWakes = false;
3525
+ strictEpoll = false;
3329
3526
  entered = false;
3527
+ enteredSignals = 0;
3528
+ raisedOnEntry;
3330
3529
  onRaise;
3331
3530
  muted;
3332
3531
  signals;
@@ -3357,6 +3556,10 @@ var init_wasi_host = __esm({
3357
3556
  this.o = { ...o, kernel: { sys, call: call2 } };
3358
3557
  this.startCwd = o.cwd;
3359
3558
  this.fds = new WasiFds(this.o.kernel, o.fs);
3559
+ this.creds = new CredCache(
3560
+ () => this.o.kernel.call({ op: "proc-cred" }),
3561
+ o.credGen ?? o.shared
3562
+ );
3360
3563
  if (o.shared) this.fds.share(o.shared, true);
3361
3564
  else if (o.forked) this.fds.restore(o.forked.fds, o.forked.cloexec);
3362
3565
  else this.fds.setup(o.cwd, o.inherited ?? [], o.preopenRoot === true);
@@ -3396,7 +3599,7 @@ var init_wasi_host = __esm({
3396
3599
  own.call(this.o.fs, path, idOf(uid), idOf(gid), follow2, handle);
3397
3600
  };
3398
3601
  const caller = () => {
3399
- const cred = this.o.kernel.call({ op: "proc-cred" });
3602
+ const cred = this.creds.get();
3400
3603
  return [cred.euid, cred.egid];
3401
3604
  };
3402
3605
  const owner = (st, out) => {
@@ -3501,7 +3704,7 @@ var init_wasi_host = __esm({
3501
3704
  }),
3502
3705
  umount2: (tp, tl, flags) => void this.o.kernel.call({ op: "umount", target: path(tp, tl), flags }),
3503
3706
  cred_get: (out) => {
3504
- const cred = this.o.kernel.call({ op: "proc-cred" });
3707
+ const cred = this.creds.get();
3505
3708
  const view = mem.view();
3506
3709
  view.getUint32(out + 20, true);
3507
3710
  IDS.forEach((key, i) => void view.setUint32(out + i * 4, cred[key], true));
@@ -3511,7 +3714,7 @@ var init_wasi_host = __esm({
3511
3714
  IDS.forEach((key, i) => {
3512
3715
  if (ids[i] !== -1) change[key] = ids[i] >>> 0;
3513
3716
  });
3514
- void this.o.kernel.call({ op: "proc-setcred", change });
3717
+ void this.creds.change(() => this.o.kernel.call({ op: "proc-setcred", change }));
3515
3718
  },
3516
3719
  ...semImports(this),
3517
3720
  ...lockImports({
@@ -3535,7 +3738,7 @@ var init_wasi_host = __esm({
3535
3738
  }
3536
3739
  }),
3537
3740
  groups_get: (buf, cap, count) => {
3538
- const { groups } = this.o.kernel.call({ op: "proc-cred" });
3741
+ const { groups } = this.creds.get();
3539
3742
  if (cap !== 0 && cap < groups.length) throw new WasiError("EINVAL");
3540
3743
  const shown = cap === 0 ? [] : groups;
3541
3744
  const view = mem.view();
@@ -3548,7 +3751,9 @@ var init_wasi_host = __esm({
3548
3751
  if (n < 0 || n > MAX_GROUPS) throw new WasiError("EINVAL");
3549
3752
  const view = mem.view();
3550
3753
  const groups = Array.from({ length: n }, (_, i) => view.getUint32(buf + i * 4, true));
3551
- void this.o.kernel.call({ op: "proc-setcred", change: { groups } });
3754
+ void this.creds.change(
3755
+ () => this.o.kernel.call({ op: "proc-setcred", change: { groups } })
3756
+ );
3552
3757
  },
3553
3758
  sigaction_set: (sig, disposition, flags) => {
3554
3759
  if (!this.signals) return E.NOSYS;
@@ -3563,6 +3768,24 @@ var init_wasi_host = __esm({
3563
3768
  view.setUint32(old + 4, oldHi, true);
3564
3769
  }) : E.NOSYS,
3565
3770
  sigmask_poll: (lo, hi, inPtr, outPtr, n, nevents) => this.sigmask ? this.maskedPoll(this.sigmask, [lo, hi], [inPtr, outPtr, n, nevents]) : E.NOSYS,
3771
+ sigmask_epoll_wait: (lo, hi, epfd, events, max, timeout, nevents) => this.sigmask ? this.maskedEpoll(
3772
+ this.sigmask,
3773
+ [lo, hi],
3774
+ nevents,
3775
+ (epoll) => epoll(epfd, events, max, timeout, nevents)
3776
+ ) : E.NOSYS,
3777
+ sigwait: (lo, _hi, timeout, out) => {
3778
+ const mask = this.sigmask;
3779
+ if (!mask) return E.NOSYS;
3780
+ mem.view().setUint32(out, 0, true);
3781
+ return mask.sigwait(
3782
+ lo,
3783
+ timeout,
3784
+ (set) => void this.o.kernel.call({ op: "sig-waiting", tid: mask.tid, set }),
3785
+ (sig) => void mem.view().setUint32(out, sig, true),
3786
+ this.entered
3787
+ );
3788
+ },
3566
3789
  sigpending_get: (out) => {
3567
3790
  if (!this.sigmask) return E.NOSYS;
3568
3791
  mem.view().setBigUint64(out, BigInt(this.sigmask.pending()), true);
@@ -3595,6 +3818,7 @@ var init_wasi_host = __esm({
3595
3818
  try {
3596
3819
  this.mem.view().setUint32(nevents, 0, true);
3597
3820
  if (mask.deliverUnblocked()) return E.INTR;
3821
+ this.settleEntry(mask);
3598
3822
  if (n > 0) return this.poll(inPtr, outPtr, n, nevents);
3599
3823
  return this.entered ? E.INTR : this.suspend();
3600
3824
  } finally {
@@ -3602,6 +3826,23 @@ var init_wasi_host = __esm({
3602
3826
  mask.restore(old);
3603
3827
  }
3604
3828
  }
3829
+ epollWait;
3830
+ settleEntry(mask) {
3831
+ if (this.entered && (this.enteredSignals & ~mask.blockedBits()) === 0) this.entered = false;
3832
+ }
3833
+ maskedEpoll(mask, set, nevents, wait2) {
3834
+ const old = mask.swap(set[0], set[1]);
3835
+ try {
3836
+ this.mem.view().setUint32(nevents, 0, true);
3837
+ if (mask.deliverUnblocked()) return E.INTR;
3838
+ this.settleEntry(mask);
3839
+ this.epollWait ??= wasixEpollImports(this).epoll_wait;
3840
+ return wait2(this.epollWait) ?? E.SUCCESS;
3841
+ } finally {
3842
+ mask.deliverUnblocked();
3843
+ mask.restore(old);
3844
+ }
3845
+ }
3605
3846
  suspend() {
3606
3847
  for (; ; ) {
3607
3848
  try {
@@ -3624,7 +3865,7 @@ var init_wasi_host = __esm({
3624
3865
  return this.cache;
3625
3866
  }
3626
3867
  now(id) {
3627
- if (id === CLOCK.REALTIME) return BigInt(Date.now()) * NS_PER_MS2;
3868
+ if (id === CLOCK.REALTIME) return BigInt(Date.now()) * NS_PER_MS3;
3628
3869
  if (id === CLOCK.MONOTONIC) {
3629
3870
  return MONOTONIC_BASE + BigInt(Math.round(performance.now() * 1e6));
3630
3871
  }
@@ -3958,7 +4199,7 @@ var init_wasi_host = __esm({
3958
4199
  return this.fds.kind(fd, e) === "file" ? this.changed(fd, e, n) : n;
3959
4200
  } catch (err) {
3960
4201
  const broken = err.code === "EPIPE";
3961
- if (broken && this.fds.kind(fd, e) !== "socket") throw new WasiExit(SIGPIPE_EXIT);
4202
+ if (broken && this.fds.kind(fd, e) !== "socket") this.brokenPipe();
3962
4203
  throw err;
3963
4204
  }
3964
4205
  }
@@ -3970,6 +4211,18 @@ var init_wasi_host = __esm({
3970
4211
  }
3971
4212
  return this.file(fd, "write").write(data);
3972
4213
  }
4214
+ brokenPipe() {
4215
+ let action;
4216
+ try {
4217
+ action = this.o.kernel.call({ op: "proc-kill-self", sig: SIG.PIPE, probe: true });
4218
+ } catch {
4219
+ action = "terminate";
4220
+ }
4221
+ if (action !== "terminate") return;
4222
+ const mask = this.sigmask;
4223
+ if (!mask?.blocks(SIG.PIPE)) throw new WasiExit(SIGPIPE_EXIT);
4224
+ this.o.kernel.call({ op: "thread-kill", tid: mask.tid, sig: SIG.PIPE });
4225
+ }
3973
4226
  read(fd, max) {
3974
4227
  const e = this.fds.get(fd);
3975
4228
  if (e.type === "kernel") {
@@ -4153,7 +4406,7 @@ var init_wasi_host = __esm({
4153
4406
  current ??= statOf(path);
4154
4407
  return current[field2] ?? current.mtimeMs ?? now;
4155
4408
  };
4156
- const pick = (set, setNow, value2, field2) => flags & setNow ? now : flags & set ? Number(value2 / NS_PER_MS2) : kept(field2);
4409
+ const pick = (set, setNow, value2, field2) => flags & setNow ? now : flags & set ? Number(value2 / NS_PER_MS3) : kept(field2);
4157
4410
  (follow2 ? this.o.fs.utimes : this.o.fs.lutimes).call(
4158
4411
  this.o.fs,
4159
4412
  path,
@@ -4744,69 +4997,6 @@ var init_async_sab = __esm({
4744
4997
  }
4745
4998
  });
4746
4999
 
4747
- // src/kernel/signals.ts
4748
- function defaultAction(sig) {
4749
- if (sig === SIG.CONT) return "continue";
4750
- if (STOPPING.has(sig)) return "stop";
4751
- return IGNORED_BY_DEFAULT.has(sig) ? "ignore" : "terminate";
4752
- }
4753
- function sigbit(sig) {
4754
- return 1 << sig;
4755
- }
4756
- function signalsIn(mask) {
4757
- const out = [];
4758
- for (let sig = 1; sig <= 31; sig++) if (mask & sigbit(sig)) out.push(sig);
4759
- return out;
4760
- }
4761
- var SIG, IGNORED_BY_DEFAULT, STOPPING, SIGNAL_BY_NAME;
4762
- var init_signals = __esm({
4763
- "src/kernel/signals.ts"() {
4764
- "use strict";
4765
- SIG = {
4766
- HUP: 1,
4767
- INT: 2,
4768
- QUIT: 3,
4769
- ILL: 4,
4770
- TRAP: 5,
4771
- ABRT: 6,
4772
- BUS: 7,
4773
- FPE: 8,
4774
- KILL: 9,
4775
- USR1: 10,
4776
- SEGV: 11,
4777
- USR2: 12,
4778
- PIPE: 13,
4779
- ALRM: 14,
4780
- TERM: 15,
4781
- STKFLT: 16,
4782
- CHLD: 17,
4783
- CONT: 18,
4784
- STOP: 19,
4785
- TSTP: 20,
4786
- TTIN: 21,
4787
- TTOU: 22,
4788
- URG: 23,
4789
- XCPU: 24,
4790
- XFSZ: 25,
4791
- VTALRM: 26,
4792
- PROF: 27,
4793
- WINCH: 28,
4794
- POLL: 29,
4795
- PWR: 30,
4796
- SYS: 31
4797
- };
4798
- IGNORED_BY_DEFAULT = /* @__PURE__ */ new Set([SIG.CHLD, SIG.URG, SIG.WINCH]);
4799
- STOPPING = /* @__PURE__ */ new Set([SIG.STOP, SIG.TSTP, SIG.TTIN, SIG.TTOU]);
4800
- SIGNAL_BY_NAME = {
4801
- SIGINT: SIG.INT,
4802
- SIGTERM: SIG.TERM,
4803
- SIGKILL: SIG.KILL,
4804
- SIGSTOP: SIG.STOP,
4805
- SIGCONT: SIG.CONT
4806
- };
4807
- }
4808
- });
4809
-
4810
5000
  // src/version.ts
4811
5001
  function procVersion() {
4812
5002
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -4816,7 +5006,7 @@ var KERNEL_VERSION, OS_RELEASE;
4816
5006
  var init_version = __esm({
4817
5007
  "src/version.ts"() {
4818
5008
  "use strict";
4819
- KERNEL_VERSION = true ? "1.103.4" : "0.0.0-dev";
5009
+ KERNEL_VERSION = true ? "1.106.3" : "0.0.0-dev";
4820
5010
  OS_RELEASE = "6.0.0-slicc";
4821
5011
  }
4822
5012
  });
@@ -4838,7 +5028,11 @@ function modeOf(mode) {
4838
5028
  function callError(result, op) {
4839
5029
  const { errno: errno2, message: message2 } = result;
4840
5030
  const detailed = typeof message2 === "string" && message2 !== errno2 && DETAILED.has(op);
4841
- return new JsCallError(errno2, detailed ? `${op}: ${message2}` : op);
5031
+ return new JsCallError(
5032
+ errno2,
5033
+ detailed ? `${op}: ${message2}` : op,
5034
+ detailed ? message2 : void 0
5035
+ );
4842
5036
  }
4843
5037
  function untilAborted(work, signal) {
4844
5038
  if (!signal) return work;
@@ -4865,10 +5059,12 @@ var init_js_kernel = __esm({
4865
5059
  init_async_sab();
4866
5060
  JsCallError = class extends Error {
4867
5061
  code;
4868
- constructor(code2, what) {
5062
+ detail;
5063
+ constructor(code2, what, detail) {
4869
5064
  super(`${what}: ${code2}`);
4870
5065
  this.name = "JsCallError";
4871
5066
  this.code = code2;
5067
+ this.detail = detail;
4872
5068
  }
4873
5069
  };
4874
5070
  DETAILED = /* @__PURE__ */ new Set([
@@ -5783,6 +5979,29 @@ var init_js_exit = __esm({
5783
5979
  });
5784
5980
 
5785
5981
  // src/process/js/js-fetch.ts
5982
+ function cut(err) {
5983
+ if (!(err instanceof JsCallError) || err.code !== "EIO") return err;
5984
+ return Object.assign(new Error("other side closed"), {
5985
+ name: "SocketError",
5986
+ code: "UND_ERR_SOCKET"
5987
+ });
5988
+ }
5989
+ function givenNames(given) {
5990
+ if (given === void 0 || given instanceof Headers) return [];
5991
+ const pairs = Array.isArray(given) ? given : Object.entries(given);
5992
+ return pairs.map((pair) => String(pair[0]).toLowerCase());
5993
+ }
5994
+ function inOrder(headers, given) {
5995
+ const all = new Map(headers);
5996
+ const out = [];
5997
+ for (const name2 of [...givenNames(given), ...all.keys()]) {
5998
+ const value2 = all.get(name2);
5999
+ if (value2 === void 0) continue;
6000
+ all.delete(name2);
6001
+ out.push([name2, value2]);
6002
+ }
6003
+ return out;
6004
+ }
5786
6005
  function withoutFragment(url) {
5787
6006
  url.hash = "";
5788
6007
  return url.href;
@@ -5809,9 +6028,7 @@ function checkUrl(url) {
5809
6028
  if (protocol !== "http:" && protocol !== "https:") {
5810
6029
  throw failed(new JsCallError("EPROTONOSUPPORT", protocol));
5811
6030
  }
5812
- if (badPort(parsed) && !local2(url)) {
5813
- throw failed(Object.assign(new Error("bad port"), { code: "EACCES" }));
5814
- }
6031
+ if (badPort(parsed)) throw failed(new Error("bad port"));
5815
6032
  }
5816
6033
  function rewrite(hop, status2, location) {
5817
6034
  const next2 = new URL(location, hop.url);
@@ -5823,6 +6040,9 @@ function rewrite(hop, status2, location) {
5823
6040
  );
5824
6041
  }
5825
6042
  const toGet = (status2 === 301 || status2 === 302) && hop.method === "POST" || status2 === 303 && hop.method !== "GET" && hop.method !== "HEAD";
6043
+ if (hop.stream && !toGet) {
6044
+ throw failed(new JsCallError("EIO", `a ${status2} redirect would send a streamed body again`));
6045
+ }
5826
6046
  const crossOrigin = next2.origin !== new URL(hop.url).origin;
5827
6047
  const headers = hop.headers.filter(
5828
6048
  ([name2]) => !(toGet && BODY_HEADERS.has(name2.toLowerCase())) && !(crossOrigin && CREDENTIALS.has(name2.toLowerCase()))
@@ -5989,6 +6209,44 @@ async function bodyOf(request, cap, signal) {
5989
6209
  }
5990
6210
  return out;
5991
6211
  }
6212
+ function streams(known, request, init, url) {
6213
+ if (known.streamingBodies !== true || !(init?.body instanceof ReadableStream)) return false;
6214
+ return request.method !== "GET" && request.method !== "HEAD" && !local2(url);
6215
+ }
6216
+ async function pump(kernel, handle, stream, signal) {
6217
+ const reader = stream.getReader();
6218
+ const stop = () => void reader.cancel(signal.reason).catch(() => void 0);
6219
+ signal.addEventListener("abort", stop, { once: true });
6220
+ try {
6221
+ await pumpFrom(kernel, handle, reader, signal);
6222
+ } finally {
6223
+ signal.removeEventListener("abort", stop);
6224
+ }
6225
+ }
6226
+ async function pumpFrom(kernel, handle, reader, signal) {
6227
+ for (; ; ) {
6228
+ let bytes;
6229
+ try {
6230
+ const next2 = await reader.read();
6231
+ if (next2.done) break;
6232
+ bytes = bytesOf(next2.value);
6233
+ } catch (err) {
6234
+ await reader.cancel(err).catch(() => void 0);
6235
+ await kernel.raw({ op: "net-close", handle });
6236
+ return;
6237
+ }
6238
+ if (bytes.length === 0) continue;
6239
+ const taken = await kernel.blocking({ op: "net-write", handle, bytes }, signal).then(
6240
+ () => true,
6241
+ () => false
6242
+ );
6243
+ if (!taken) {
6244
+ await reader.cancel().catch(() => void 0);
6245
+ return;
6246
+ }
6247
+ }
6248
+ await kernel.raw({ op: "net-end", handle });
6249
+ }
5992
6250
  function fetchOp(kernel) {
5993
6251
  const traits = /* @__PURE__ */ new Map();
5994
6252
  const traitsOf = (url) => {
@@ -6008,8 +6266,9 @@ function fetchOp(kernel) {
6008
6266
  url: hop.url,
6009
6267
  method: hop.method,
6010
6268
  headers: hop.headers,
6011
- ...hop.body ? { body: hop.body } : {}
6269
+ ...hop.stream ? { stream: true } : hop.body ? { body: hop.body } : {}
6012
6270
  });
6271
+ if (hop.stream) void pump(kernel, handle, hop.stream, signal);
6013
6272
  try {
6014
6273
  const r = await kernel.blocking({ op: "net-head", handle }, signal);
6015
6274
  signal.throwIfAborted();
@@ -6041,7 +6300,7 @@ function fetchOp(kernel) {
6041
6300
  } catch (err) {
6042
6301
  settle();
6043
6302
  await close(handle);
6044
- throw signal.aborted ? signal.reason : new TypeError("terminated", { cause: err });
6303
+ throw signal.aborted ? signal.reason : new TypeError("terminated", { cause: cut(err) });
6045
6304
  }
6046
6305
  const bytes = r.ok && r.kind === "bytes" ? r.bytes : new Uint8Array(0);
6047
6306
  if (bytes.length > 0) {
@@ -6103,15 +6362,17 @@ function fetchOp(kernel) {
6103
6362
  throw failed(new JsCallError("ENOTSUP", `redirect: ${request.redirect}`));
6104
6363
  }
6105
6364
  const url = withoutFragment(new URL(request.url));
6106
- const bytes = await bodyOf(request, known.maxRequestBody, signal);
6365
+ const streamed = streams(known, request, init, url);
6366
+ const bytes = streamed ? void 0 : await bodyOf(request, known.maxRequestBody, signal);
6107
6367
  if (bytes === OVER) {
6108
6368
  return withMeta(plain(413, `request body over ${known.maxRequestBody} bytes`), url, false);
6109
6369
  }
6110
6370
  let hop = {
6111
6371
  url,
6112
6372
  method: request.method,
6113
- headers: [...request.headers],
6114
- body: bytes
6373
+ headers: inOrder(request.headers, init?.headers),
6374
+ body: bytes,
6375
+ ...streamed && request.body ? { stream: request.body } : {}
6115
6376
  };
6116
6377
  for (let hops = 0; ; hops++) {
6117
6378
  const head = await send(hop, signal);
@@ -6122,8 +6383,7 @@ function fetchOp(kernel) {
6122
6383
  return respond(head, hop.method, redirected, known.encodedBodies, signal);
6123
6384
  }
6124
6385
  await close(head.handle);
6125
- if (request.redirect === "error")
6126
- throw failed(new JsCallError("EREDIRECT", "unexpected redirect"));
6386
+ if (request.redirect === "error") throw failed(new Error("unexpected redirect"));
6127
6387
  if (hops >= MAX_REDIRECTS) throw failed(new JsCallError("ELOOP", hop.url));
6128
6388
  [hop, known] = await redirect(hop, head.status, location, known);
6129
6389
  }
@@ -10228,6 +10488,12 @@ var init_js_tty = __esm({
10228
10488
  function failed4(err) {
10229
10489
  return new TypeError("websocket failed", { cause: err });
10230
10490
  }
10491
+ function openError(err) {
10492
+ if (!(err instanceof JsCallError) || err.detail === void 0) return err;
10493
+ const prefix = `${err.code}: `;
10494
+ const message2 = err.detail.startsWith(prefix) ? err.detail.slice(prefix.length) : err.detail;
10495
+ return Object.assign(new Error(message2), { code: err.code });
10496
+ }
10231
10497
  function socketUrl(input) {
10232
10498
  const url = new URL(input);
10233
10499
  if (url.protocol === "http:") url.protocol = "ws:";
@@ -10269,7 +10535,7 @@ function websocketOp(kernel) {
10269
10535
  protocol = (r.ok && r.kind === "json" ? r.json : {}).protocol;
10270
10536
  } catch (err) {
10271
10537
  await free();
10272
- throw signal.aborted ? signal.reason : failed4(err);
10538
+ throw signal.aborted ? signal.reason : failed4(openError(err));
10273
10539
  }
10274
10540
  let settle;
10275
10541
  let lose;
@@ -11807,7 +12073,7 @@ function orphanContents(stream) {
11807
12073
  if (live.ranged) return live.ranged.read(0, live.ranged.size());
11808
12074
  return live.data?.slice(0, live.len ?? live.data.length) ?? new Uint8Array(0);
11809
12075
  }
11810
- function vfsPromoter(Fs, sys, streams, livePath) {
12076
+ function vfsPromoter(Fs, sys, streams2, livePath) {
11811
12077
  const promoted = /* @__PURE__ */ new Map();
11812
12078
  return (stream) => {
11813
12079
  if (stream.sliccKernelFd !== void 0 || !isVfsFile(Fs, stream)) return;
@@ -11827,11 +12093,11 @@ function vfsPromoter(Fs, sys, streams, livePath) {
11827
12093
  );
11828
12094
  promoted.set(stream.shared, kfd);
11829
12095
  }
11830
- streams.attachFile(stream, kfd);
12096
+ streams2.attachFile(stream, kfd);
11831
12097
  };
11832
12098
  }
11833
- function describeForFork(Fs, sys, streams, livePath) {
11834
- const promote = vfsPromoter(Fs, sys, streams, livePath);
12099
+ function describeForFork(Fs, sys, streams2, livePath) {
12100
+ const promote = vfsPromoter(Fs, sys, streams2, livePath);
11835
12101
  const out = [];
11836
12102
  for (const stream of Fs.streams) {
11837
12103
  if (!stream) continue;
@@ -11855,7 +12121,7 @@ function kernelEntry2(stream, kernel) {
11855
12121
  const access = kind === "tty" ? O_RDWR4 : (stream.flags ?? O_RDWR4) & O_ACCMODE4;
11856
12122
  return { fd: stream.fd, kernel, kind, flags: access, ...cloexec };
11857
12123
  }
11858
- function describeInherited(Fs, sys, streams, livePath, actions = []) {
12124
+ function describeInherited(Fs, sys, streams2, livePath, actions = []) {
11859
12125
  const table = /* @__PURE__ */ new Map();
11860
12126
  for (const stream of Fs.streams) {
11861
12127
  if (stream) table.set(stream.fd, { stream, cloexec: closesOnExec(stream) });
@@ -11870,7 +12136,7 @@ function describeInherited(Fs, sys, streams, livePath, actions = []) {
11870
12136
  for (const [fd, { stream, cloexec }] of table) {
11871
12137
  if (fd > 2 && !cloexec) slots3.set(fd, stream);
11872
12138
  }
11873
- const promote = vfsPromoter(Fs, sys, streams, livePath);
12139
+ const promote = vfsPromoter(Fs, sys, streams2, livePath);
11874
12140
  const out = [];
11875
12141
  for (const [fd, stream] of slots3) {
11876
12142
  promote(stream);
@@ -11899,50 +12165,50 @@ function place(Fs, stream, fd) {
11899
12165
  Fs.closeStream(stream.fd);
11900
12166
  return moved;
11901
12167
  }
11902
- function placeholder(Fs, streams, entry) {
12168
+ function placeholder(Fs, streams2, entry) {
11903
12169
  const access = entry.flags ?? O_RDWR4;
11904
- if (entry.kind === "socket") return streams.socketStream(access);
12170
+ if (entry.kind === "socket") return streams2.socketStream(access);
11905
12171
  if (entry.kind === "tty") return Fs.open("/dev/tty", O_RDWR4);
11906
12172
  if (entry.kind === "stream" || entry.kind === "clipboard" || entry.kind === "sealed")
11907
12173
  return Fs.open("/dev/null", access);
11908
12174
  Fs.mkdirTree(PLACEHOLDER_DIR);
11909
12175
  return Fs.open(`${PLACEHOLDER_DIR}/${entry.fd}`, access | O_CREAT3);
11910
12176
  }
11911
- function asFifo(stream, streams, identity) {
11912
- const inos = streamInos.get(streams) ?? /* @__PURE__ */ new Map();
11913
- streamInos.set(streams, inos);
12177
+ function asFifo(stream, streams2, identity) {
12178
+ const inos = streamInos.get(streams2) ?? /* @__PURE__ */ new Map();
12179
+ streamInos.set(streams2, inos);
11914
12180
  const fixed = inos.get(identity) ?? nextStreamIno++;
11915
12181
  inos.set(identity, fixed);
11916
12182
  const node = stream.node;
11917
- streams.describe(stream, `pipe:[${fixed}]`, () => ({
12183
+ streams2.describe(stream, `pipe:[${fixed}]`, () => ({
11918
12184
  ...node.node_ops?.getattr?.(node),
11919
12185
  mode: FIFO_MODE,
11920
12186
  ino: fixed,
11921
12187
  size: 0
11922
12188
  }));
11923
12189
  }
11924
- function placeKernelStream(Fs, streams, entry) {
11925
- const stream = place(Fs, placeholder(Fs, streams, entry), entry.fd);
12190
+ function placeKernelStream(Fs, streams2, entry) {
12191
+ const stream = place(Fs, placeholder(Fs, streams2, entry), entry.fd);
11926
12192
  if (entry.kind === "file") {
11927
- streams.attachFile(stream, entry.kernel);
11928
- streams.sizeFromKernel(stream, entry.kernel);
11929
- } else if (entry.kind === "socket") streams.attachSocket(stream, entry.kernel);
11930
- else streams.attach(stream, entry.kernel, entry.kind === "tty");
11931
- if (entry.kind === "clipboard") streams.reportClose(entry.kernel);
11932
- if (entry.kind === "sealed" || entry.kind === "clipboard") streams.nameDevice(stream, entry.kind);
11933
- if (entry.kind === "tty") streams.nameTerminal(stream);
12193
+ streams2.attachFile(stream, entry.kernel);
12194
+ streams2.sizeFromKernel(stream, entry.kernel);
12195
+ } else if (entry.kind === "socket") streams2.attachSocket(stream, entry.kernel);
12196
+ else streams2.attach(stream, entry.kernel, entry.kind === "tty");
12197
+ if (entry.kind === "clipboard") streams2.reportClose(entry.kernel);
12198
+ if (entry.kind === "sealed" || entry.kind === "clipboard") streams2.nameDevice(stream, entry.kind);
12199
+ if (entry.kind === "tty") streams2.nameTerminal(stream);
11934
12200
  if (entry.kind === "stream") {
11935
- asFifo(stream, streams, entry.desc !== void 0 ? `d${entry.desc}` : `k${entry.kernel}`);
12201
+ asFifo(stream, streams2, entry.desc !== void 0 ? `d${entry.desc}` : `k${entry.kernel}`);
11936
12202
  }
11937
12203
  setCloseOnExec(stream, entry.cloexec === true);
11938
12204
  return stream;
11939
12205
  }
11940
- function restoreForkedStreams(Fs, streams, table) {
12206
+ function restoreForkedStreams(Fs, streams2, table) {
11941
12207
  for (const stream of Fs.streams) if (stream) Fs.closeStream(stream.fd);
11942
12208
  for (const entry of table) {
11943
12209
  try {
11944
12210
  if ("kernel" in entry) {
11945
- placeKernelStream(Fs, streams, entry);
12211
+ placeKernelStream(Fs, streams2, entry);
11946
12212
  } else {
11947
12213
  const placed = place(
11948
12214
  Fs,
@@ -12010,14 +12276,14 @@ function forkRestarted(deps, state, snapshotAt) {
12010
12276
  let memory = state.memory;
12011
12277
  let seen = snapshotAt;
12012
12278
  return restarted2(() => {
12013
- const streams = deps.describeFork();
12279
+ const streams2 = deps.describeFork();
12014
12280
  const now = deps.deliveries?.();
12015
12281
  if (now !== seen) {
12016
12282
  seen = now;
12017
12283
  const live = deps.memory?.();
12018
12284
  if (live) memory = new Uint8Array(live.buffer).slice();
12019
12285
  }
12020
- const forked = { ...state, memory, streams, cwd: deps.Fs.cwd() };
12286
+ const forked = { ...state, memory, streams: streams2, cwd: deps.Fs.cwd() };
12021
12287
  return deps.transport.call(
12022
12288
  { op: "proc-fork", state: forked, restart: true },
12023
12289
  Infinity,
@@ -12329,6 +12595,8 @@ var init_process_signals = __esm({
12329
12595
  unwinding = false;
12330
12596
  quieted = 0;
12331
12597
  delivered = 0;
12598
+ raised = 0;
12599
+ entering = 0;
12332
12600
  raw;
12333
12601
  header;
12334
12602
  hooks;
@@ -12391,9 +12659,18 @@ var init_process_signals = __esm({
12391
12659
  const header = this.header;
12392
12660
  const pending = Atomics.load(header, SAB_I_SIGNALS) & ~Atomics.load(header, SAB_I_BLOCKED) | Atomics.load(header, SAB_I_TIMERS) | Atomics.load(header, SAB_I_KILLED);
12393
12661
  if (pending === 0) return false;
12394
- this.deliver();
12662
+ if (this.entering === 0) this.raised = this.quieted > 0 ? -1 : 0;
12663
+ this.entering++;
12664
+ try {
12665
+ this.deliver();
12666
+ } finally {
12667
+ this.entering--;
12668
+ }
12395
12669
  return true;
12396
12670
  }
12671
+ raisedOnEntry() {
12672
+ return this.raised;
12673
+ }
12397
12674
  deliver() {
12398
12675
  if (this.quieted > 0) return;
12399
12676
  const killed = Atomics.load(this.header, SAB_I_KILLED);
@@ -12406,6 +12683,7 @@ var init_process_signals = __esm({
12406
12683
  const pending = blocked === 0 ? Atomics.exchange(this.header, SAB_I_SIGNALS, 0) : Atomics.and(this.header, SAB_I_SIGNALS, blocked) & ~blocked;
12407
12684
  if (this.depth <= 1) this.lastDelivered = pending | (timers & 1 ? sigbit(SIG.ALRM) : 0);
12408
12685
  if (pending !== 0 || timers !== 0) this.delivered++;
12686
+ this.raised |= pending | (timers & 1 ? sigbit(SIG.ALRM) : 0) | (timers & ~1 ? -1 : 0);
12409
12687
  for (let which = 0; which < 3; which++) {
12410
12688
  if (timers & 1 << which) this.hooks.timer?.(which);
12411
12689
  }
@@ -12428,7 +12706,7 @@ function resolved(Fs, addr) {
12428
12706
  return { family: "unix", path: normalizePath(path) };
12429
12707
  }
12430
12708
  function createSocketKernel(deps) {
12431
- const { transport, Fs, sys, streams } = deps;
12709
+ const { transport, Fs, sys, streams: streams2 } = deps;
12432
12710
  const call2 = (req) => {
12433
12711
  const r = transport.call(req, Number.POSITIVE_INFINITY, req.op);
12434
12712
  if (!r.ok) throw new SyscallError(r.errno);
@@ -12464,12 +12742,12 @@ function createSocketKernel(deps) {
12464
12742
  const install = (k, nonblock, cloexec = false) => {
12465
12743
  let stream;
12466
12744
  try {
12467
- stream = streams.socketStream(O_RDWR5 | (nonblock ? O_NONBLOCK2 : 0));
12745
+ stream = streams2.socketStream(O_RDWR5 | (nonblock ? O_NONBLOCK2 : 0));
12468
12746
  } catch (e) {
12469
12747
  sys.close(k);
12470
12748
  throw e;
12471
12749
  }
12472
- streams.attachSocket(stream, k);
12750
+ streams2.attachSocket(stream, k);
12473
12751
  setCloseOnExec(stream, cloexec);
12474
12752
  return stream.fd;
12475
12753
  };
@@ -12748,9 +13026,9 @@ function kernelSys(transport) {
12748
13026
  }
12749
13027
  };
12750
13028
  }
12751
- function wireKernelFd(Fs, streams, entry) {
13029
+ function wireKernelFd(Fs, streams2, entry) {
12752
13030
  if (entry.device && openDevice(Fs, entry.fd, entry.device)) return;
12753
- placeKernelStream(Fs, streams, {
13031
+ placeKernelStream(Fs, streams2, {
12754
13032
  ...entry,
12755
13033
  kind: entry.device ? "stream" : entry.kind,
12756
13034
  kernel: entry.fd
@@ -12775,7 +13053,7 @@ function openAt(Fs, fd, path, flags) {
12775
13053
  }
12776
13054
  return true;
12777
13055
  }
12778
- function wireKernelStdio(Fs, streams, sys) {
13056
+ function wireKernelStdio(Fs, streams2, sys) {
12779
13057
  for (const fd of [0, 1, 2]) {
12780
13058
  const stream = Fs.getStream(fd);
12781
13059
  if (!stream) continue;
@@ -12786,11 +13064,11 @@ function wireKernelStdio(Fs, streams, sys) {
12786
13064
  const flags = sys?.access ? stream.flags & ~O_ACCMODE5 | accessMode(sys.access(fd)) : stream.flags;
12787
13065
  Fs.closeStream(fd);
12788
13066
  const kernel = { fd, kernel: fd, kind, flags };
12789
- placeKernelStream(Fs, streams, kernel).flags = flags;
13067
+ placeKernelStream(Fs, streams2, kernel).flags = flags;
12790
13068
  continue;
12791
13069
  }
12792
- streams.attach(stream, fd);
12793
- streams.nameTerminal(stream);
13070
+ streams2.attach(stream, fd);
13071
+ streams2.nameTerminal(stream);
12794
13072
  }
12795
13073
  }
12796
13074
  function glueBody(glue) {
@@ -12889,6 +13167,11 @@ function credSyncTransport(gated, early, cred) {
12889
13167
  }
12890
13168
  };
12891
13169
  }
13170
+ function sigpipeSpared(transport) {
13171
+ const req = { op: "proc-kill-self", sig: SIG.PIPE, probe: true };
13172
+ const r = transport.call(req, Number.POSITIVE_INFINITY, "proc-kill-self");
13173
+ return r.ok && !(r.kind === "json" && r.json === "terminate");
13174
+ }
12892
13175
  async function runWasmProcess(init, port3, deps = {}) {
12893
13176
  const signals = new SignalGate(
12894
13177
  createSyncSabTransport(init.sab, port3, {
@@ -12996,10 +13279,10 @@ async function runWasmProcess(init, port3, deps = {}) {
12996
13279
  });
12997
13280
  early = () => signals.quiet(() => vfs.flushDirty());
12998
13281
  closeDropsLocks(running.FS, sys);
12999
- const sigpipe = () => running.sliccSigpipe?.() === 1;
13282
+ const sigpipe = () => running.sliccSigpipe?.() === 1 || sigpipeSpared(gated);
13000
13283
  const restartable = () => signals.restartable();
13001
13284
  const owners = init.owners ? { owners: true } : {};
13002
- const streams = new KernelStreams(running.FS, sys, {
13285
+ const streams2 = new KernelStreams(running.FS, sys, {
13003
13286
  sigpipe,
13004
13287
  restartable,
13005
13288
  ...owners,
@@ -13007,21 +13290,21 @@ async function runWasmProcess(init, port3, deps = {}) {
13007
13290
  });
13008
13291
  trackCloseOnExec(running.FS);
13009
13292
  quietQuit(running.FS, (on) => {
13010
- streams.quitting = on;
13293
+ streams2.quitting = on;
13011
13294
  });
13012
- atExit = () => streams.exiting();
13295
+ atExit = () => streams2.exiting();
13013
13296
  useMounts(running.FS, init.env, true);
13014
13297
  useZeroDevices(running.FS);
13015
13298
  useProcfs(running.FS, sys, init.pid);
13016
- if (init.fork) restoreForkedStreams(running.FS, streams, init.fork.streams ?? []);
13299
+ if (init.fork) restoreForkedStreams(running.FS, streams2, init.fork.streams ?? []);
13017
13300
  else {
13018
- wireKernelStdio(running.FS, streams, sys);
13019
- for (const entry of init.fds ?? []) wireKernelFd(running.FS, streams, entry);
13301
+ wireKernelStdio(running.FS, streams2, sys);
13302
+ for (const entry of init.fds ?? []) wireKernelFd(running.FS, streams2, entry);
13020
13303
  }
13021
13304
  const pipefs = ownValue(running, "PIPEFS");
13022
- if (pipefs) streams.usePipes(pipefs);
13023
- streams.useControllingTerminal();
13024
- streams.useKernelFdMetadata();
13305
+ if (pipefs) streams2.usePipes(pipefs);
13306
+ streams2.useControllingTerminal();
13307
+ streams2.useKernelFdMetadata();
13025
13308
  useDevFd(running.FS);
13026
13309
  useDevRemoval(running.FS);
13027
13310
  useFileMmap(running.FS, {
@@ -13041,9 +13324,9 @@ async function runWasmProcess(init, port3, deps = {}) {
13041
13324
  restartable,
13042
13325
  memory: () => memory,
13043
13326
  deliveries: () => signals.deliveries(),
13044
- describeFork: () => describeForFork(running.FS, sys, streams, livePath),
13045
- inherit: (actions) => describeInherited(running.FS, sys, streams, livePath, actions),
13046
- stdioPromoter: () => vfsPromoter(running.FS, sys, streams, livePath),
13327
+ describeFork: () => describeForFork(running.FS, sys, streams2, livePath),
13328
+ inherit: (actions) => describeInherited(running.FS, sys, streams2, livePath, actions),
13329
+ stdioPromoter: () => vfsPromoter(running.FS, sys, streams2, livePath),
13047
13330
  ...callerOwner(running.FS, init)
13048
13331
  });
13049
13332
  running.sliccKernel.http = createHttpKernel(transport);
@@ -13052,15 +13335,15 @@ async function runWasmProcess(init, port3, deps = {}) {
13052
13335
  transport,
13053
13336
  Fs: running.FS,
13054
13337
  sys,
13055
- streams,
13338
+ streams: streams2,
13056
13339
  sigpipe,
13057
13340
  restartable
13058
13341
  });
13059
- return runWithFlush(running, init, streams, vfs);
13342
+ return runWithFlush(running, init, streams2, vfs);
13060
13343
  }
13061
- function runWithFlush(running, init, streams, vfs) {
13344
+ function runWithFlush(running, init, streams2, vfs) {
13062
13345
  try {
13063
- return streams.exitStatus(runMain(running, init));
13346
+ return streams2.exitStatus(runMain(running, init));
13064
13347
  } finally {
13065
13348
  try {
13066
13349
  vfs.flush();
@@ -13312,7 +13595,7 @@ var init_wasi_module = __esm({
13312
13595
  });
13313
13596
 
13314
13597
  // src/process/wasi/wasi-sigmask.ts
13315
- var UNBLOCKABLE, LIBC_UNBLOCKABLE, SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK, kernelBits, libcBits, apply, WasiSigmask;
13598
+ var UNBLOCKABLE, LIBC_UNBLOCKABLE, FOREVER2, NS_PER_MS4, POLL_MS, SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK, kernelBits, libcBits, apply, WasiSigmask;
13316
13599
  var init_wasi_sigmask = __esm({
13317
13600
  "src/process/wasi/wasi-sigmask.ts"() {
13318
13601
  "use strict";
@@ -13321,6 +13604,9 @@ var init_wasi_sigmask = __esm({
13321
13604
  init_wasi_abi();
13322
13605
  UNBLOCKABLE = sigbit(SIG.KILL) | sigbit(SIG.STOP);
13323
13606
  LIBC_UNBLOCKABLE = 1 << SIG.KILL - 1 | 1 << SIG.STOP - 1;
13607
+ FOREVER2 = 0xffffffffffffffffn;
13608
+ NS_PER_MS4 = 1000000n;
13609
+ POLL_MS = 50;
13324
13610
  SIG_BLOCK = 0;
13325
13611
  SIG_UNBLOCK = 1;
13326
13612
  SIG_SETMASK = 2;
@@ -13337,10 +13623,12 @@ var init_wasi_sigmask = __esm({
13337
13623
  header;
13338
13624
  deliver;
13339
13625
  process;
13340
- constructor(header, deliver, process) {
13626
+ tid;
13627
+ constructor(header, deliver, process, tid = 1) {
13341
13628
  this.header = header;
13342
13629
  this.deliver = deliver;
13343
13630
  this.process = process;
13631
+ this.tid = tid;
13344
13632
  this.lo = libcBits(Atomics.load(header, SAB_I_BLOCKED));
13345
13633
  this.hi = Atomics.load(header, SAB_I_BLOCKED_HI);
13346
13634
  }
@@ -13374,6 +13662,12 @@ var init_wasi_sigmask = __esm({
13374
13662
  this.set(SIG_SETMASK, lo, hi, () => {
13375
13663
  });
13376
13664
  }
13665
+ blockedBits() {
13666
+ return Atomics.load(this.header, SAB_I_BLOCKED);
13667
+ }
13668
+ blocks(sig) {
13669
+ return (Atomics.load(this.header, SAB_I_BLOCKED) & sigbit(sig)) !== 0;
13670
+ }
13377
13671
  inherited() {
13378
13672
  return [kernelBits(this.lo), this.hi];
13379
13673
  }
@@ -13381,6 +13675,47 @@ var init_wasi_sigmask = __esm({
13381
13675
  Atomics.and(this.header, SAB_I_SIGNALS, ~sigbit(sig));
13382
13676
  if (this.process) Atomics.and(this.process, SAB_I_SIGNALS, ~sigbit(sig));
13383
13677
  }
13678
+ sigwait(setLo, timeoutNs, publish, took, entered = false) {
13679
+ const set = kernelBits(setLo | 0);
13680
+ const value2 = BigInt.asUintN(64, timeoutNs);
13681
+ const deadline = value2 === FOREVER2 ? Number.POSITIVE_INFINITY : performance.now() + Number((value2 + NS_PER_MS4 - 1n) / NS_PER_MS4);
13682
+ publish(set);
13683
+ try {
13684
+ for (; ; ) {
13685
+ const seen = Atomics.load(this.header, SAB_I_SIGNALS);
13686
+ const sig = this.take(set);
13687
+ if (sig !== 0) {
13688
+ took(sig);
13689
+ return E.SUCCESS;
13690
+ }
13691
+ if (entered || this.deliverUnblocked() || this.interrupted()) return E.INTR;
13692
+ const left = deadline - performance.now();
13693
+ if (left <= 0) return E.AGAIN;
13694
+ Atomics.wait(this.header, SAB_I_SIGNALS, seen, Math.min(left, POLL_MS));
13695
+ }
13696
+ } finally {
13697
+ publish(0);
13698
+ }
13699
+ }
13700
+ take(set) {
13701
+ for (const header of this.process ? [this.header, this.process] : [this.header]) {
13702
+ const ready = Atomics.load(header, SAB_I_SIGNALS) & set;
13703
+ if (ready === 0) continue;
13704
+ const bit = ready & -ready;
13705
+ if ((Atomics.and(header, SAB_I_SIGNALS, ~bit) & bit) !== 0) return 31 - Math.clz32(bit);
13706
+ }
13707
+ return 0;
13708
+ }
13709
+ interrupted() {
13710
+ const killed = this.process ?? this.header;
13711
+ if (Atomics.load(killed, SAB_I_KILLED) !== 0) {
13712
+ this.deliver();
13713
+ return true;
13714
+ }
13715
+ if (Atomics.load(killed, SAB_I_STOP) !== 1) return false;
13716
+ while (Atomics.load(killed, SAB_I_STOP) === 1) Atomics.wait(killed, SAB_I_STOP, 1);
13717
+ return true;
13718
+ }
13384
13719
  pending() {
13385
13720
  const own = Atomics.load(this.header, SAB_I_SIGNALS);
13386
13721
  return libcBits(own | (this.process ? Atomics.load(this.process, SAB_I_SIGNALS) : 0));
@@ -13739,91 +14074,6 @@ var init_wasix_fork = __esm({
13739
14074
  }
13740
14075
  });
13741
14076
 
13742
- // src/process/wasi/wasix-epoll.ts
13743
- function timeoutMs(ns) {
13744
- const value2 = BigInt.asUintN(64, ns);
13745
- if (value2 === FOREVER) return -1;
13746
- const ms = (value2 + NS_PER_MS3 - 1n) / NS_PER_MS3;
13747
- return ms > BigInt(MAX_TIMEOUT_MS) ? -1 : Number(ms);
13748
- }
13749
- function wasixEpollImports(host) {
13750
- const { mem, fds, o } = host;
13751
- const call2 = (req) => o.kernel.call(req);
13752
- const kernelFd = (fd, refusal2) => {
13753
- const e = fds.find(fd);
13754
- if (!e) throw new WasiError("EBADF");
13755
- if (e.type !== "kernel") throw new WasiError(refusal2);
13756
- };
13757
- const writeEvents2 = (ptr, events) => {
13758
- const view = mem.view();
13759
- events.forEach((ev, i) => {
13760
- const at = ptr + i * EVENT_SIZE;
13761
- mem.bytes(at, EVENT_SIZE).fill(0);
13762
- view.setUint32(at, ev.events, true);
13763
- mem.bytes(at + DATA_OFFSET, DATA_SIZE).set(ev.data);
13764
- });
13765
- };
13766
- return {
13767
- epoll_create: (out) => {
13768
- const fd = call2({ op: "epoll-create" });
13769
- fds.adopt(fd, "stream", false);
13770
- mem.view().setUint32(out, fd, true);
13771
- },
13772
- epoll_ctl: (epfd, op, fd, event) => {
13773
- const how = OPS[op];
13774
- if (!how) throw new WasiError("EINVAL");
13775
- kernelFd(epfd, "EINVAL");
13776
- kernelFd(fd, "EPERM");
13777
- if (how !== "del" && event === 0) throw new WasiError("EINVAL");
13778
- const events = event === 0 ? 0 : mem.view().getUint32(event, true);
13779
- const data = event === 0 ? [] : [...mem.bytes(event + DATA_OFFSET, DATA_SIZE)];
13780
- call2({ op: "epoll-ctl", epfd, how, fd, events, data });
13781
- },
13782
- epoll_wait: (epfd, ptr, maxevents, timeout, out) => {
13783
- mem.view().setUint32(out, 0, true);
13784
- if ((maxevents | 0) <= 0) throw new WasiError("EINVAL");
13785
- kernelFd(epfd, "EINVAL");
13786
- const max = Math.min(maxevents | 0, MAX_EVENTS);
13787
- const ms = host.entered ? 0 : timeoutMs(timeout);
13788
- const events = call2({ op: "epoll-wait", epfd, max, timeoutMs: ms });
13789
- if (host.entered && events.length === 0 && timeoutMs(timeout) !== 0) return E.INTR;
13790
- writeEvents2(ptr, events);
13791
- mem.view().setUint32(out, events.length, true);
13792
- return E.SUCCESS;
13793
- },
13794
- fd_event: (initial, flags, out) => {
13795
- const value2 = BigInt.asUintN(64, initial);
13796
- if (value2 > EVENTFD_MAX) throw new WasiError("EINVAL");
13797
- const fd = call2({
13798
- op: "eventfd-open",
13799
- initial: value2.toString(),
13800
- semaphore: (flags & EVENTFD_SEMAPHORE) !== 0
13801
- });
13802
- fds.adopt(fd, "stream", (flags & EVENTFD_NONBLOCK) !== 0);
13803
- mem.view().setUint32(out, fd, true);
13804
- }
13805
- };
13806
- }
13807
- var EVENT_SIZE, DATA_OFFSET, DATA_SIZE, MAX_EVENTS, FOREVER, MAX_TIMEOUT_MS, NS_PER_MS3, EVENTFD_SEMAPHORE, EVENTFD_NONBLOCK, EVENTFD_MAX, OPS;
13808
- var init_wasix_epoll = __esm({
13809
- "src/process/wasi/wasix-epoll.ts"() {
13810
- "use strict";
13811
- init_wasi_abi();
13812
- init_wasi_files();
13813
- EVENT_SIZE = 32;
13814
- DATA_OFFSET = 8;
13815
- DATA_SIZE = 24;
13816
- MAX_EVENTS = 4096;
13817
- FOREVER = 0xffffffffffffffffn;
13818
- MAX_TIMEOUT_MS = 2147483647;
13819
- NS_PER_MS3 = 1000000n;
13820
- EVENTFD_SEMAPHORE = 1;
13821
- EVENTFD_NONBLOCK = 4;
13822
- EVENTFD_MAX = 0xfffffffffffffffen;
13823
- OPS = ["add", "set", "del", "mod"];
13824
- }
13825
- });
13826
-
13827
14077
  // src/process/wasi/wasix-ffi.ts
13828
14078
  function read(view, at, type) {
13829
14079
  if (type === "i32") return view.getInt32(at, true);
@@ -14730,7 +14980,7 @@ function posixSignal(sig) {
14730
14980
  function nsToMs(ns) {
14731
14981
  return Math.ceil(Number(ns) / 1e6);
14732
14982
  }
14733
- var FDFLAGSEXT_CLOEXEC, SPAWN_OP_SIZE, SPAWN_OPS, RIGHTS_FD_WRITE, ICANON2, ECHO2, FUTEX_SLICE_MS, EINTR_LIBC, MAIN_HANDLE, WasixHost;
14983
+ var FDFLAGSEXT_CLOEXEC, SPAWN_OP_SIZE, SPAWN_OPS, RIGHTS_FD_WRITE, ICANON2, ECHO2, FUTEX_SLICE_MS, EINTR_LIBC, STRICT_EPOLL_LIBC, MAIN_HANDLE, WasixHost;
14734
14984
  var init_wasix_host = __esm({
14735
14985
  "src/process/wasi/wasix-host.ts"() {
14736
14986
  "use strict";
@@ -14754,6 +15004,7 @@ var init_wasix_host = __esm({
14754
15004
  ECHO2 = 8;
14755
15005
  FUTEX_SLICE_MS = 50;
14756
15006
  EINTR_LIBC = 22;
15007
+ STRICT_EPOLL_LIBC = 29;
14757
15008
  MAIN_HANDLE = 2147483647;
14758
15009
  WasixHost = class _WasixHost {
14759
15010
  process;
@@ -14772,6 +15023,7 @@ var init_wasix_host = __esm({
14772
15023
  driver,
14773
15024
  () => (this.threads?.tid ?? MAIN_TID) !== MAIN_TID
14774
15025
  );
15026
+ if (module) host.strictEpoll = (libcVersion(module) ?? 0) >= STRICT_EPOLL_LIBC;
14775
15027
  if (module && !WebAssembly.Module.imports(module).some((i) => i.name === "fd_fdflags_set")) {
14776
15028
  host.fds.implicitCloexec = true;
14777
15029
  host.interruptWakes = (libcVersion(module) ?? 0) < EINTR_LIBC;
@@ -15232,6 +15484,7 @@ __export(wasi_runtime_exports, {
15232
15484
  });
15233
15485
  function wireSignals(host, gate) {
15234
15486
  host.interrupted = () => gate.interrupt();
15487
+ host.raisedOnEntry = () => gate.raisedOnEntry();
15235
15488
  host.quietly = (fn) => gate.quiet(fn);
15236
15489
  }
15237
15490
  function catchUpFirst(host, sync) {
@@ -15257,6 +15510,7 @@ function delivering(ns, table, host, driver, before) {
15257
15510
  if (driver.idle) {
15258
15511
  before?.();
15259
15512
  host.entered = host.interrupted?.() === true;
15513
+ host.enteredSignals = host.entered ? host.raisedOnEntry?.() ?? -1 : 0;
15260
15514
  }
15261
15515
  return fn(...args);
15262
15516
  };
@@ -15271,7 +15525,7 @@ function sigmaskOf(module, sab, gate, threads, process) {
15271
15525
  }
15272
15526
  if (threads) threads.blocked = () => loadBlocked(header);
15273
15527
  const shared = process && new Int32Array(process, 0, SAB_HEADER_I32);
15274
- return new WasiSigmask(header, () => gate.deliver(), shared);
15528
+ return new WasiSigmask(header, () => gate.deliver(), shared, threads?.tid ?? MAIN_TID);
15275
15529
  }
15276
15530
  function enosys(module, name2, foreign) {
15277
15531
  const type = foreign?.[module]?.[name2];
@@ -15625,7 +15879,8 @@ async function runWasiProcess(init, port3) {
15625
15879
  ),
15626
15880
  procTree(call2, id.pid)
15627
15881
  ),
15628
- ...descriptors(init, fork, threads)
15882
+ ...descriptors(init, fork, threads),
15883
+ ...threads ? { credGen: threads.ids } : {}
15629
15884
  });
15630
15885
  host.sigmask = sigmaskOf(module, init.sab, gate, threads);
15631
15886
  if (threads) {