@ai-ecoverse/slicc-kernel 1.97.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.
package/dist/node.js CHANGED
@@ -6168,10 +6168,10 @@ function envOf(pkg, raw) {
6168
6168
  }
6169
6169
  return env;
6170
6170
  }
6171
- function envFields(merged) {
6171
+ function envFields(merged2) {
6172
6172
  const env = {};
6173
6173
  const unset = [];
6174
- for (const [key, value] of Object.entries(merged)) {
6174
+ for (const [key, value] of Object.entries(merged2)) {
6175
6175
  if (value === null) unset.push(key);
6176
6176
  else env[key] = value;
6177
6177
  }
@@ -11047,7 +11047,7 @@ function mountTable(mounts = []) {
11047
11047
  }
11048
11048
 
11049
11049
  // src/version.ts
11050
- var KERNEL_VERSION = true ? "1.97.0" : "0.0.0-dev";
11050
+ var KERNEL_VERSION = true ? "1.97.1" : "0.0.0-dev";
11051
11051
  var OS_RELEASE = "6.0.0-slicc";
11052
11052
  function procVersion() {
11053
11053
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -11724,23 +11724,115 @@ async function epollSyscall(req, proc) {
11724
11724
  }
11725
11725
  }
11726
11726
 
11727
- // src/kernel/host-ops.ts
11728
- var HOST_OPS = [
11729
- "lock",
11730
- "unlock",
11731
- "async-submit",
11732
- "async-wait",
11733
- "async-take",
11734
- "async-resolve",
11735
- "async-hold",
11736
- "async-cancel",
11737
- "async-settle",
11738
- "async-close"
11739
- ];
11740
- var json3 = (value) => ({ ok: true, kind: "json", json: value });
11741
- var done2 = { ok: true, kind: "void" };
11727
+ // src/kernel/locks.ts
11728
+ var overlaps = (a, b) => a.start < b.end && b.start < a.end;
11729
+ var clashes = (lock, owner, want) => lock.owner !== owner && overlaps(lock, want) && (lock.kind === "write" || want.kind === "write");
11730
+ function lockRange(start2, len) {
11731
+ if (!Number.isSafeInteger(start2) || !Number.isSafeInteger(len)) throw new KernelError("EINVAL");
11732
+ const from = len < 0 ? start2 + len : start2;
11733
+ const end = len === 0 ? Number.POSITIVE_INFINITY : len < 0 ? start2 : start2 + len;
11734
+ if (from < 0) throw new KernelError("EINVAL");
11735
+ return { start: from, end };
11736
+ }
11742
11737
  var LockTable = class {
11738
+ records = /* @__PURE__ */ new Map();
11739
+ blocked = /* @__PURE__ */ new Map();
11740
+ wakers = /* @__PURE__ */ new Map();
11743
11741
  held = /* @__PURE__ */ new Map();
11742
+ holder(key, owner, want) {
11743
+ return this.records.get(key)?.find((lock) => clashes(lock, owner, want));
11744
+ }
11745
+ set(key, owner, kind, start2, end) {
11746
+ if (kind !== "unlock" && this.holder(key, owner, { key, kind, start: start2, end })) return false;
11747
+ const range = { start: start2, end };
11748
+ const kept = [];
11749
+ for (const lock of this.records.get(key) ?? []) {
11750
+ if (lock.owner !== owner || !overlaps(lock, range)) kept.push(lock);
11751
+ else {
11752
+ if (lock.start < start2) kept.push({ ...lock, end: start2 });
11753
+ if (lock.end > end) kept.push({ ...lock, start: end });
11754
+ }
11755
+ }
11756
+ if (kind !== "unlock") kept.push({ owner, kind, start: start2, end });
11757
+ this.store(key, merged(kept));
11758
+ this.wake(key);
11759
+ return true;
11760
+ }
11761
+ async wait(key, owner, kind, range, blocking) {
11762
+ const want = { key, kind, ...range };
11763
+ let signal;
11764
+ for (; ; ) {
11765
+ const holder = this.holder(key, owner, want);
11766
+ if (!holder) {
11767
+ this.set(key, owner, kind, range.start, range.end);
11768
+ return;
11769
+ }
11770
+ if (this.waitsOn(holder.owner, owner)) throw new KernelError("EDEADLK");
11771
+ signal ??= blocking();
11772
+ if (signal.aborted) throw new KernelError("EINTR");
11773
+ this.blocked.set(owner, want);
11774
+ try {
11775
+ await this.changed(key, signal);
11776
+ } finally {
11777
+ this.blocked.delete(owner);
11778
+ }
11779
+ }
11780
+ }
11781
+ waitsOn(from, target) {
11782
+ const seen = /* @__PURE__ */ new Set();
11783
+ for (let at = from; at !== void 0 && !seen.has(at); ) {
11784
+ seen.add(at);
11785
+ const want = this.blocked.get(at);
11786
+ if (!want) return false;
11787
+ const holder = this.holder(want.key, at, want);
11788
+ if (!holder) return false;
11789
+ if (holder.owner === target) return true;
11790
+ at = holder.owner;
11791
+ }
11792
+ return false;
11793
+ }
11794
+ changed(key, signal) {
11795
+ return new Promise((resolve2, reject) => {
11796
+ const set2 = this.wakers.get(key) ?? /* @__PURE__ */ new Set();
11797
+ this.wakers.set(key, set2);
11798
+ const done4 = () => {
11799
+ set2.delete(wake);
11800
+ if (set2.size === 0 && this.wakers.get(key) === set2) this.wakers.delete(key);
11801
+ signal.removeEventListener("abort", abort);
11802
+ };
11803
+ const wake = () => {
11804
+ done4();
11805
+ resolve2();
11806
+ };
11807
+ const abort = () => {
11808
+ done4();
11809
+ reject(new KernelError("EINTR"));
11810
+ };
11811
+ set2.add(wake);
11812
+ signal.addEventListener("abort", abort, { once: true });
11813
+ });
11814
+ }
11815
+ wake(key) {
11816
+ for (const wake of [...this.wakers.get(key) ?? []]) wake();
11817
+ }
11818
+ store(key, locks) {
11819
+ if (locks.length === 0) this.records.delete(key);
11820
+ else this.records.set(key, locks);
11821
+ }
11822
+ holds(owner) {
11823
+ for (const locks of this.records.values())
11824
+ if (locks.some((l) => l.owner === owner)) return true;
11825
+ return false;
11826
+ }
11827
+ dropFile(key, owner) {
11828
+ const locks = this.records.get(key);
11829
+ if (!locks?.some((l) => l.owner === owner)) return;
11830
+ this.store(
11831
+ key,
11832
+ locks.filter((l) => l.owner !== owner)
11833
+ );
11834
+ this.wake(key);
11835
+ }
11744
11836
  lock(pid, path, exclusive, fd) {
11745
11837
  const holders = this.held.get(path) ?? /* @__PURE__ */ new Map();
11746
11838
  for (const [other, h] of holders) if (other !== pid && (exclusive || h.exclusive)) return false;
@@ -11764,8 +11856,39 @@ var LockTable = class {
11764
11856
  }
11765
11857
  release(pid) {
11766
11858
  for (const path of [...this.held.keys()]) this.unlock(pid, path);
11859
+ for (const key of [...this.records.keys()]) this.dropFile(key, pid);
11767
11860
  }
11768
11861
  };
11862
+ function merged(locks) {
11863
+ const sorted = [...locks].sort((a, b) => a.owner - b.owner || a.start - b.start);
11864
+ const out = [];
11865
+ for (const lock of sorted) {
11866
+ const last = out[out.length - 1];
11867
+ if (last && last.owner === lock.owner && last.kind === lock.kind && last.end >= lock.start) {
11868
+ last.end = Math.max(last.end, lock.end);
11869
+ } else out.push({ ...lock });
11870
+ }
11871
+ return out;
11872
+ }
11873
+
11874
+ // src/kernel/host-ops.ts
11875
+ var HOST_OPS = [
11876
+ "lock",
11877
+ "unlock",
11878
+ "lk-set",
11879
+ "lk-get",
11880
+ "lk-close",
11881
+ "async-submit",
11882
+ "async-wait",
11883
+ "async-take",
11884
+ "async-resolve",
11885
+ "async-hold",
11886
+ "async-cancel",
11887
+ "async-settle",
11888
+ "async-close"
11889
+ ];
11890
+ var json3 = (value) => ({ ok: true, kind: "json", json: value });
11891
+ var done2 = { ok: true, kind: "void" };
11769
11892
  var KEPT_OPS = /* @__PURE__ */ new Set(["fd-write"]);
11770
11893
  var unknownSettled = false;
11771
11894
  var AsyncOps = class {
@@ -11902,6 +12025,10 @@ async function hostSyscall(req, ctx) {
11902
12025
  case "unlock":
11903
12026
  ctx.locks?.unlock(ctx.pid, req.path);
11904
12027
  return done2;
12028
+ case "lk-set":
12029
+ case "lk-get":
12030
+ case "lk-close":
12031
+ return recordLock2(req, ctx);
11905
12032
  case "async-submit":
11906
12033
  if (!ctx.valid(req.req)) throw new KernelError("EINVAL");
11907
12034
  if (req.ack) ctx.ops.ack(req.ack);
@@ -11924,6 +12051,33 @@ async function hostSyscall(req, ctx) {
11924
12051
  return done2;
11925
12052
  }
11926
12053
  }
12054
+ async function recordLock2(req, ctx) {
12055
+ const { locks, fileKey } = ctx;
12056
+ if (!locks || !fileKey) throw new KernelError("ENOLCK");
12057
+ const owner = ctx.owner?.() ?? ctx.pid;
12058
+ const target = {
12059
+ ...req.path !== void 0 ? { path: req.path } : {},
12060
+ ...req.fd !== void 0 ? { fd: req.fd } : {}
12061
+ };
12062
+ if (req.op === "lk-close") {
12063
+ locks.dropFile(await fileKey(target, "close"), owner);
12064
+ return done2;
12065
+ }
12066
+ const range = lockRange(req.start, req.len);
12067
+ const key = await fileKey(target, req.kind);
12068
+ if (req.op === "lk-get") {
12069
+ const held = locks.holder(key, owner, { key, kind: req.kind, ...range });
12070
+ if (!held) return json3(null);
12071
+ const len = held.end === Number.POSITIVE_INFINITY ? 0 : held.end - held.start;
12072
+ return json3({ kind: held.kind, pid: held.owner, start: held.start, len });
12073
+ }
12074
+ if (req.kind !== "unlock" && req.wait) {
12075
+ await locks.wait(key, owner, req.kind, range, ctx.blocking);
12076
+ return done2;
12077
+ }
12078
+ if (!locks.set(key, owner, req.kind, range.start, range.end)) throw new KernelError("EAGAIN");
12079
+ return done2;
12080
+ }
11927
12081
 
11928
12082
  // src/kernel/net/loopback-transport.ts
11929
12083
  var LOOPBACK_TRAITS = {
@@ -15118,6 +15272,8 @@ var WasmProcess = class {
15118
15272
  if (isHostSyscall(req)) {
15119
15273
  return await hostSyscall(req, {
15120
15274
  pid: this.pid,
15275
+ owner: () => this.lockOwner(),
15276
+ fileKey: (target, kind) => this.lockKey(target, kind),
15121
15277
  locks: this.options.locks,
15122
15278
  ops: this.asyncOps,
15123
15279
  blocking: () => this.blockingSignal(cancelled),
@@ -15144,6 +15300,44 @@ var WasmProcess = class {
15144
15300
  throw e;
15145
15301
  }
15146
15302
  }
15303
+ lockOwners = /* @__PURE__ */ new Set();
15304
+ lockChecked = /* @__PURE__ */ new Set();
15305
+ lockOwner() {
15306
+ const owner = this.options.jobs?.shown(this.pid) ?? this.pid;
15307
+ this.lockOwners.add(owner);
15308
+ return owner;
15309
+ }
15310
+ async lockPath(target, want) {
15311
+ if (target.fd !== void 0) {
15312
+ const st = await this.fds.get(target.fd).file.stat?.();
15313
+ if (!st || st.orphan) throw new KernelError("EBADF");
15314
+ return st.path;
15315
+ }
15316
+ if (target.path === void 0) throw new KernelError("EINVAL");
15317
+ if (!target.path.startsWith("/")) throw new KernelError("EINVAL");
15318
+ const path = target.path;
15319
+ const g = this.guarded();
15320
+ const checked = `${want}:${path}`;
15321
+ if (g && want !== 0 && !this.lockChecked.has(checked)) {
15322
+ await openable(g, "lock", path, want, false);
15323
+ this.lockChecked.add(checked);
15324
+ }
15325
+ return path;
15326
+ }
15327
+ async lockKey(target, kind) {
15328
+ const want = kind === "read" ? R_OK : kind === "write" ? W_OK : 0;
15329
+ const path = await this.lockPath(target, want);
15330
+ const st = await this.options.fs.stat?.(path);
15331
+ if (!st) throw new KernelError("ENOENT");
15332
+ return st.ino === void 0 ? path : `${st.dev ?? 0}:${st.ino}`;
15333
+ }
15334
+ async dropRecordLocks(fd) {
15335
+ const { locks } = this.options;
15336
+ const owner = this.options.jobs?.shown(this.pid) ?? this.pid;
15337
+ if (!locks?.holds(owner) || !this.fds.has(fd)) return;
15338
+ const key = await this.lockKey({ fd }, "close").catch(() => void 0);
15339
+ if (key !== void 0) locks.dropFile(key, owner);
15340
+ }
15147
15341
  refuseIfPending(restart) {
15148
15342
  if (restart && this.options.hasPending?.()) throw new KernelError("EINTR");
15149
15343
  }
@@ -15455,6 +15649,7 @@ var WasmProcess = class {
15455
15649
  };
15456
15650
  case "fd-close": {
15457
15651
  this.options.locks?.closed(this.pid, req.fd);
15652
+ await this.dropRecordLocks(req.fd);
15458
15653
  const channel = this.fds.get(req.fd).file.clipboard;
15459
15654
  if (channel) channel.stamp = await this.clipboardStamp();
15460
15655
  await Promise.resolve(this.fds.close(req.fd)).catch(async (err) => {
@@ -16047,6 +16242,7 @@ var WasmProcess = class {
16047
16242
  this.clearAlarm();
16048
16243
  this.interrupt.abort();
16049
16244
  this.options.locks?.release(this.pid);
16245
+ for (const owner of this.lockOwners) this.options.locks?.release(owner);
16050
16246
  this.asyncOps.close();
16051
16247
  for (const [target, sig] of this.deathSignals) this.sendDeath(target, sig);
16052
16248
  this.deathSignals.clear();
@@ -21952,10 +22148,10 @@ var Chunks = class {
21952
22148
  const old = this.blobs[index];
21953
22149
  if (from === 0 && n >= (old?.size ?? 0)) this.blobs[index] = new Blob([part]);
21954
22150
  else {
21955
- const merged = new Uint8Array(Math.max(old?.size ?? 0, from + n));
21956
- if (old) merged.set(new Uint8Array(await old.arrayBuffer()));
21957
- merged.set(part, from);
21958
- this.blobs[index] = new Blob([merged]);
22151
+ const merged2 = new Uint8Array(Math.max(old?.size ?? 0, from + n));
22152
+ if (old) merged2.set(new Uint8Array(await old.arrayBuffer()));
22153
+ merged2.set(part, from);
22154
+ this.blobs[index] = new Blob([merged2]);
21959
22155
  }
21960
22156
  done4 += n;
21961
22157
  }