@ai-ecoverse/slicc-kernel 1.96.0 → 1.97.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.
@@ -7695,10 +7695,10 @@ function envOf(pkg, raw) {
7695
7695
  }
7696
7696
  return env;
7697
7697
  }
7698
- function envFields(merged) {
7698
+ function envFields(merged2) {
7699
7699
  const env = {};
7700
7700
  const unset = [];
7701
- for (const [key, value] of Object.entries(merged)) {
7701
+ for (const [key, value] of Object.entries(merged2)) {
7702
7702
  if (value === null) unset.push(key);
7703
7703
  else env[key] = value;
7704
7704
  }
@@ -12054,7 +12054,7 @@ function mountTable(mounts = []) {
12054
12054
  }
12055
12055
 
12056
12056
  // src/version.ts
12057
- var KERNEL_VERSION = true ? "1.96.0" : "0.0.0-dev";
12057
+ var KERNEL_VERSION = true ? "1.97.1" : "0.0.0-dev";
12058
12058
  var OS_RELEASE = "6.0.0-slicc";
12059
12059
  function procVersion() {
12060
12060
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -12731,23 +12731,115 @@ async function epollSyscall(req, proc) {
12731
12731
  }
12732
12732
  }
12733
12733
 
12734
- // src/kernel/host-ops.ts
12735
- var HOST_OPS = [
12736
- "lock",
12737
- "unlock",
12738
- "async-submit",
12739
- "async-wait",
12740
- "async-take",
12741
- "async-resolve",
12742
- "async-hold",
12743
- "async-cancel",
12744
- "async-settle",
12745
- "async-close"
12746
- ];
12747
- var json3 = (value) => ({ ok: true, kind: "json", json: value });
12748
- var done2 = { ok: true, kind: "void" };
12734
+ // src/kernel/locks.ts
12735
+ var overlaps = (a, b) => a.start < b.end && b.start < a.end;
12736
+ var clashes = (lock, owner, want) => lock.owner !== owner && overlaps(lock, want) && (lock.kind === "write" || want.kind === "write");
12737
+ function lockRange(start2, len) {
12738
+ if (!Number.isSafeInteger(start2) || !Number.isSafeInteger(len)) throw new KernelError("EINVAL");
12739
+ const from = len < 0 ? start2 + len : start2;
12740
+ const end = len === 0 ? Number.POSITIVE_INFINITY : len < 0 ? start2 : start2 + len;
12741
+ if (from < 0) throw new KernelError("EINVAL");
12742
+ return { start: from, end };
12743
+ }
12749
12744
  var LockTable = class {
12745
+ records = /* @__PURE__ */ new Map();
12746
+ blocked = /* @__PURE__ */ new Map();
12747
+ wakers = /* @__PURE__ */ new Map();
12750
12748
  held = /* @__PURE__ */ new Map();
12749
+ holder(key, owner, want) {
12750
+ return this.records.get(key)?.find((lock) => clashes(lock, owner, want));
12751
+ }
12752
+ set(key, owner, kind, start2, end) {
12753
+ if (kind !== "unlock" && this.holder(key, owner, { key, kind, start: start2, end })) return false;
12754
+ const range = { start: start2, end };
12755
+ const kept = [];
12756
+ for (const lock of this.records.get(key) ?? []) {
12757
+ if (lock.owner !== owner || !overlaps(lock, range)) kept.push(lock);
12758
+ else {
12759
+ if (lock.start < start2) kept.push({ ...lock, end: start2 });
12760
+ if (lock.end > end) kept.push({ ...lock, start: end });
12761
+ }
12762
+ }
12763
+ if (kind !== "unlock") kept.push({ owner, kind, start: start2, end });
12764
+ this.store(key, merged(kept));
12765
+ this.wake(key);
12766
+ return true;
12767
+ }
12768
+ async wait(key, owner, kind, range, blocking) {
12769
+ const want = { key, kind, ...range };
12770
+ let signal;
12771
+ for (; ; ) {
12772
+ const holder = this.holder(key, owner, want);
12773
+ if (!holder) {
12774
+ this.set(key, owner, kind, range.start, range.end);
12775
+ return;
12776
+ }
12777
+ if (this.waitsOn(holder.owner, owner)) throw new KernelError("EDEADLK");
12778
+ signal ??= blocking();
12779
+ if (signal.aborted) throw new KernelError("EINTR");
12780
+ this.blocked.set(owner, want);
12781
+ try {
12782
+ await this.changed(key, signal);
12783
+ } finally {
12784
+ this.blocked.delete(owner);
12785
+ }
12786
+ }
12787
+ }
12788
+ waitsOn(from, target) {
12789
+ const seen = /* @__PURE__ */ new Set();
12790
+ for (let at = from; at !== void 0 && !seen.has(at); ) {
12791
+ seen.add(at);
12792
+ const want = this.blocked.get(at);
12793
+ if (!want) return false;
12794
+ const holder = this.holder(want.key, at, want);
12795
+ if (!holder) return false;
12796
+ if (holder.owner === target) return true;
12797
+ at = holder.owner;
12798
+ }
12799
+ return false;
12800
+ }
12801
+ changed(key, signal) {
12802
+ return new Promise((resolve2, reject) => {
12803
+ const set2 = this.wakers.get(key) ?? /* @__PURE__ */ new Set();
12804
+ this.wakers.set(key, set2);
12805
+ const done4 = () => {
12806
+ set2.delete(wake);
12807
+ if (set2.size === 0 && this.wakers.get(key) === set2) this.wakers.delete(key);
12808
+ signal.removeEventListener("abort", abort);
12809
+ };
12810
+ const wake = () => {
12811
+ done4();
12812
+ resolve2();
12813
+ };
12814
+ const abort = () => {
12815
+ done4();
12816
+ reject(new KernelError("EINTR"));
12817
+ };
12818
+ set2.add(wake);
12819
+ signal.addEventListener("abort", abort, { once: true });
12820
+ });
12821
+ }
12822
+ wake(key) {
12823
+ for (const wake of [...this.wakers.get(key) ?? []]) wake();
12824
+ }
12825
+ store(key, locks) {
12826
+ if (locks.length === 0) this.records.delete(key);
12827
+ else this.records.set(key, locks);
12828
+ }
12829
+ holds(owner) {
12830
+ for (const locks of this.records.values())
12831
+ if (locks.some((l) => l.owner === owner)) return true;
12832
+ return false;
12833
+ }
12834
+ dropFile(key, owner) {
12835
+ const locks = this.records.get(key);
12836
+ if (!locks?.some((l) => l.owner === owner)) return;
12837
+ this.store(
12838
+ key,
12839
+ locks.filter((l) => l.owner !== owner)
12840
+ );
12841
+ this.wake(key);
12842
+ }
12751
12843
  lock(pid, path, exclusive, fd) {
12752
12844
  const holders = this.held.get(path) ?? /* @__PURE__ */ new Map();
12753
12845
  for (const [other, h] of holders) if (other !== pid && (exclusive || h.exclusive)) return false;
@@ -12771,8 +12863,39 @@ var LockTable = class {
12771
12863
  }
12772
12864
  release(pid) {
12773
12865
  for (const path of [...this.held.keys()]) this.unlock(pid, path);
12866
+ for (const key of [...this.records.keys()]) this.dropFile(key, pid);
12774
12867
  }
12775
12868
  };
12869
+ function merged(locks) {
12870
+ const sorted = [...locks].sort((a, b) => a.owner - b.owner || a.start - b.start);
12871
+ const out = [];
12872
+ for (const lock of sorted) {
12873
+ const last = out[out.length - 1];
12874
+ if (last && last.owner === lock.owner && last.kind === lock.kind && last.end >= lock.start) {
12875
+ last.end = Math.max(last.end, lock.end);
12876
+ } else out.push({ ...lock });
12877
+ }
12878
+ return out;
12879
+ }
12880
+
12881
+ // src/kernel/host-ops.ts
12882
+ var HOST_OPS = [
12883
+ "lock",
12884
+ "unlock",
12885
+ "lk-set",
12886
+ "lk-get",
12887
+ "lk-close",
12888
+ "async-submit",
12889
+ "async-wait",
12890
+ "async-take",
12891
+ "async-resolve",
12892
+ "async-hold",
12893
+ "async-cancel",
12894
+ "async-settle",
12895
+ "async-close"
12896
+ ];
12897
+ var json3 = (value) => ({ ok: true, kind: "json", json: value });
12898
+ var done2 = { ok: true, kind: "void" };
12776
12899
  var KEPT_OPS = /* @__PURE__ */ new Set(["fd-write"]);
12777
12900
  var unknownSettled = false;
12778
12901
  var AsyncOps = class {
@@ -12909,6 +13032,10 @@ async function hostSyscall(req, ctx) {
12909
13032
  case "unlock":
12910
13033
  ctx.locks?.unlock(ctx.pid, req.path);
12911
13034
  return done2;
13035
+ case "lk-set":
13036
+ case "lk-get":
13037
+ case "lk-close":
13038
+ return recordLock2(req, ctx);
12912
13039
  case "async-submit":
12913
13040
  if (!ctx.valid(req.req)) throw new KernelError("EINVAL");
12914
13041
  if (req.ack) ctx.ops.ack(req.ack);
@@ -12931,6 +13058,33 @@ async function hostSyscall(req, ctx) {
12931
13058
  return done2;
12932
13059
  }
12933
13060
  }
13061
+ async function recordLock2(req, ctx) {
13062
+ const { locks, fileKey } = ctx;
13063
+ if (!locks || !fileKey) throw new KernelError("ENOLCK");
13064
+ const owner = ctx.owner?.() ?? ctx.pid;
13065
+ const target = {
13066
+ ...req.path !== void 0 ? { path: req.path } : {},
13067
+ ...req.fd !== void 0 ? { fd: req.fd } : {}
13068
+ };
13069
+ if (req.op === "lk-close") {
13070
+ locks.dropFile(await fileKey(target, "close"), owner);
13071
+ return done2;
13072
+ }
13073
+ const range = lockRange(req.start, req.len);
13074
+ const key = await fileKey(target, req.kind);
13075
+ if (req.op === "lk-get") {
13076
+ const held = locks.holder(key, owner, { key, kind: req.kind, ...range });
13077
+ if (!held) return json3(null);
13078
+ const len = held.end === Number.POSITIVE_INFINITY ? 0 : held.end - held.start;
13079
+ return json3({ kind: held.kind, pid: held.owner, start: held.start, len });
13080
+ }
13081
+ if (req.kind !== "unlock" && req.wait) {
13082
+ await locks.wait(key, owner, req.kind, range, ctx.blocking);
13083
+ return done2;
13084
+ }
13085
+ if (!locks.set(key, owner, req.kind, range.start, range.end)) throw new KernelError("EAGAIN");
13086
+ return done2;
13087
+ }
12934
13088
 
12935
13089
  // src/kernel/net/loopback-transport.ts
12936
13090
  var LOOPBACK_TRAITS = {
@@ -15461,6 +15615,8 @@ var WasmProcess = class {
15461
15615
  if (isHostSyscall(req)) {
15462
15616
  return await hostSyscall(req, {
15463
15617
  pid: this.pid,
15618
+ owner: () => this.lockOwner(),
15619
+ fileKey: (target, kind) => this.lockKey(target, kind),
15464
15620
  locks: this.options.locks,
15465
15621
  ops: this.asyncOps,
15466
15622
  blocking: () => this.blockingSignal(cancelled),
@@ -15487,6 +15643,44 @@ var WasmProcess = class {
15487
15643
  throw e;
15488
15644
  }
15489
15645
  }
15646
+ lockOwners = /* @__PURE__ */ new Set();
15647
+ lockChecked = /* @__PURE__ */ new Set();
15648
+ lockOwner() {
15649
+ const owner = this.options.jobs?.shown(this.pid) ?? this.pid;
15650
+ this.lockOwners.add(owner);
15651
+ return owner;
15652
+ }
15653
+ async lockPath(target, want) {
15654
+ if (target.fd !== void 0) {
15655
+ const st = await this.fds.get(target.fd).file.stat?.();
15656
+ if (!st || st.orphan) throw new KernelError("EBADF");
15657
+ return st.path;
15658
+ }
15659
+ if (target.path === void 0) throw new KernelError("EINVAL");
15660
+ if (!target.path.startsWith("/")) throw new KernelError("EINVAL");
15661
+ const path = target.path;
15662
+ const g = this.guarded();
15663
+ const checked = `${want}:${path}`;
15664
+ if (g && want !== 0 && !this.lockChecked.has(checked)) {
15665
+ await openable(g, "lock", path, want, false);
15666
+ this.lockChecked.add(checked);
15667
+ }
15668
+ return path;
15669
+ }
15670
+ async lockKey(target, kind) {
15671
+ const want = kind === "read" ? R_OK : kind === "write" ? W_OK : 0;
15672
+ const path = await this.lockPath(target, want);
15673
+ const st = await this.options.fs.stat?.(path);
15674
+ if (!st) throw new KernelError("ENOENT");
15675
+ return st.ino === void 0 ? path : `${st.dev ?? 0}:${st.ino}`;
15676
+ }
15677
+ async dropRecordLocks(fd) {
15678
+ const { locks } = this.options;
15679
+ const owner = this.options.jobs?.shown(this.pid) ?? this.pid;
15680
+ if (!locks?.holds(owner) || !this.fds.has(fd)) return;
15681
+ const key = await this.lockKey({ fd }, "close").catch(() => void 0);
15682
+ if (key !== void 0) locks.dropFile(key, owner);
15683
+ }
15490
15684
  refuseIfPending(restart) {
15491
15685
  if (restart && this.options.hasPending?.()) throw new KernelError("EINTR");
15492
15686
  }
@@ -15798,6 +15992,7 @@ var WasmProcess = class {
15798
15992
  };
15799
15993
  case "fd-close": {
15800
15994
  this.options.locks?.closed(this.pid, req.fd);
15995
+ await this.dropRecordLocks(req.fd);
15801
15996
  const channel = this.fds.get(req.fd).file.clipboard;
15802
15997
  if (channel) channel.stamp = await this.clipboardStamp();
15803
15998
  await Promise.resolve(this.fds.close(req.fd)).catch(async (err) => {
@@ -16390,6 +16585,7 @@ var WasmProcess = class {
16390
16585
  this.clearAlarm();
16391
16586
  this.interrupt.abort();
16392
16587
  this.options.locks?.release(this.pid);
16588
+ for (const owner of this.lockOwners) this.options.locks?.release(owner);
16393
16589
  this.asyncOps.close();
16394
16590
  for (const [target, sig] of this.deathSignals) this.sendDeath(target, sig);
16395
16591
  this.deathSignals.clear();