@ai-ecoverse/slicc-kernel 1.118.1 → 1.119.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
@@ -4303,12 +4303,14 @@ var OpfsFs = class {
4303
4303
  mounts = {};
4304
4304
  locks;
4305
4305
  lockPrefix;
4306
+ rootName;
4306
4307
  constructor(root, meta = new MemoryMeta(), channel, options = {}) {
4307
4308
  this.root = root;
4308
4309
  this.meta = sidecar(meta);
4309
4310
  this.ranged = options.ranged === true;
4310
4311
  this.locks = options.locks === void 0 ? lockManager() : options.locks ?? void 0;
4311
4312
  this.lockPrefix = `slicc-excl:${channel ?? ""}:`;
4313
+ this.rootName = channel;
4312
4314
  this.channel = channel === void 0 ? void 0 : new BroadcastChannel(channel);
4313
4315
  this.remote = channel === void 0 ? void 0 : new RemoteWatch(`${channel}:watch`);
4314
4316
  if (this.remote) this.remote.quiet = () => this.quiet();
@@ -6735,7 +6737,7 @@ function satisfies(version, range2) {
6735
6737
  }
6736
6738
 
6737
6739
  // src/version.ts
6738
- var KERNEL_VERSION = true ? "1.118.1" : "0.0.0-dev";
6740
+ var KERNEL_VERSION = true ? "1.119.1" : "0.0.0-dev";
6739
6741
  var OS_RELEASE = "6.0.0-slicc";
6740
6742
  function procVersion() {
6741
6743
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -13398,6 +13400,12 @@ var FlockTable = class {
13398
13400
  await changedAt(this.wakers, key, signal);
13399
13401
  }
13400
13402
  }
13403
+ entries() {
13404
+ const out = [];
13405
+ for (const [key, holders] of this.held)
13406
+ for (const [owner, kind] of holders) out.push([key, owner, kind]);
13407
+ return out;
13408
+ }
13401
13409
  drop(owner) {
13402
13410
  const key = this.keys.get(owner);
13403
13411
  if (key === void 0) return;
@@ -13476,6 +13484,9 @@ var LockTable = class {
13476
13484
  if (locks.length === 0) this.records.delete(key);
13477
13485
  else this.records.set(key, locks);
13478
13486
  }
13487
+ entries() {
13488
+ return [...this.records].map(([key, locks]) => [key, locks.map((l) => ({ ...l }))]);
13489
+ }
13479
13490
  holds(owner) {
13480
13491
  for (const locks of this.records.values())
13481
13492
  if (locks.some((l) => l.owner === owner)) return true;
@@ -13720,7 +13731,7 @@ async function flock(req, ctx) {
13720
13731
  const { key, owner } = await flockOf(req.fd);
13721
13732
  if (req.kind !== "unlock" && req.wait)
13722
13733
  await locks.flocks.wait(key, owner, req.kind, ctx.blocking);
13723
- else if (!locks.flocks.set(key, owner, req.kind)) throw new KernelError("EAGAIN");
13734
+ else if (!await locks.flocks.set(key, owner, req.kind)) throw new KernelError("EAGAIN");
13724
13735
  return done2;
13725
13736
  }
13726
13737
  async function recordLock2(req, ctx) {
@@ -13738,7 +13749,7 @@ async function recordLock2(req, ctx) {
13738
13749
  const range2 = lockRange(req.start, req.len);
13739
13750
  const key = await fileKey(target, req.kind, req.op === "lk-set" && req.fd !== void 0);
13740
13751
  if (req.op === "lk-get") {
13741
- const held = locks.holder(key, owner, { key, kind: req.kind, ...range2 });
13752
+ const held = await locks.holder(key, owner, { key, kind: req.kind, ...range2 });
13742
13753
  if (!held) return json3(null);
13743
13754
  const len = held.end === Number.POSITIVE_INFINITY ? 0 : held.end - held.start;
13744
13755
  return json3({ kind: held.kind, pid: held.owner, start: held.start, len });
@@ -13747,7 +13758,8 @@ async function recordLock2(req, ctx) {
13747
13758
  await locks.wait(key, owner, req.kind, range2, ctx.blocking);
13748
13759
  return done2;
13749
13760
  }
13750
- if (!locks.set(key, owner, req.kind, range2.start, range2.end)) throw new KernelError("EAGAIN");
13761
+ if (!await locks.set(key, owner, req.kind, range2.start, range2.end))
13762
+ throw new KernelError("EAGAIN");
13751
13763
  return done2;
13752
13764
  }
13753
13765
 
@@ -19740,6 +19752,343 @@ var JobTable = class {
19740
19752
  }
19741
19753
  };
19742
19754
 
19755
+ // src/kernel/lock-service.ts
19756
+ var PRUNE_MS = 1e3;
19757
+ var LOCKS_PROTOCOL = "v1";
19758
+ var LockService = class {
19759
+ kernel = crypto.randomUUID();
19760
+ table = new LockTable();
19761
+ leader = false;
19762
+ role;
19763
+ channel;
19764
+ locks;
19765
+ root;
19766
+ pending = /* @__PURE__ */ new Map();
19767
+ next = 0;
19768
+ owners = /* @__PURE__ */ new Map();
19769
+ ownerOf = /* @__PURE__ */ new Map();
19770
+ nextRemote = -1;
19771
+ tokens = /* @__PURE__ */ new Map();
19772
+ flockIds = /* @__PURE__ */ new WeakMap();
19773
+ flockOwners = /* @__PURE__ */ new Map();
19774
+ nextFlock = 1;
19775
+ granted = /* @__PURE__ */ new Map();
19776
+ waiting = /* @__PURE__ */ new Map();
19777
+ settled = Promise.resolve();
19778
+ pruner;
19779
+ flocks;
19780
+ constructor(options) {
19781
+ this.root = options.root;
19782
+ this.locks = options.locks;
19783
+ this.channel = (options.channel ?? ((n) => new BroadcastChannel(n)))(
19784
+ `slicc-locks:${LOCKS_PROTOCOL}:${this.root}`
19785
+ );
19786
+ this.channel.unref?.();
19787
+ this.channel.onmessage = ({ data }) => {
19788
+ if (isMessage(data)) void this.receive(data);
19789
+ };
19790
+ void this.locks.request(this.aliveOf(this.kernel), () => new Promise(() => {
19791
+ }));
19792
+ this.role = this.elect();
19793
+ this.flocks = {
19794
+ set: (key, owner, kind) => this.flockSet(key, owner, kind),
19795
+ wait: (key, owner, kind, blocking) => this.flockWait(key, owner, kind, blocking),
19796
+ drop: (owner) => this.flockDrop(owner)
19797
+ };
19798
+ }
19799
+ aliveOf(kernel) {
19800
+ return `slicc-locks-alive:${LOCKS_PROTOCOL}:${this.root}:${kernel}`;
19801
+ }
19802
+ elect() {
19803
+ const name2 = `slicc-locks-leader:${LOCKS_PROTOCOL}:${this.root}`;
19804
+ return new Promise((decided) => {
19805
+ void this.locks.request(name2, { ifAvailable: true }, async (lock) => {
19806
+ this.leader = lock !== null;
19807
+ decided();
19808
+ if (this.leader) await new Promise(() => {
19809
+ });
19810
+ });
19811
+ }).then(() => {
19812
+ if (this.leader) return;
19813
+ void this.locks.request(name2, async () => {
19814
+ await this.lead();
19815
+ await new Promise(() => {
19816
+ });
19817
+ });
19818
+ });
19819
+ }
19820
+ async lead() {
19821
+ this.leader = true;
19822
+ this.settled = new Promise((resolve2) => setTimeout(resolve2, ANNOUNCE_WAIT_MS));
19823
+ this.channel.postMessage({ reassert: true, from: this.kernel });
19824
+ const pending = [...this.pending.entries()];
19825
+ this.pending.clear();
19826
+ await this.settled;
19827
+ for (const [, p] of pending) void this.serve(p.ask, this.kernel).then(p.resolve, p.reject);
19828
+ }
19829
+ async receive(data) {
19830
+ if (data.reassert && data.from !== this.kernel) return this.reassert();
19831
+ if (data.to !== void 0 && data.to !== this.kernel) return;
19832
+ if (data.id !== void 0 && (data.ok !== void 0 || data.errno !== void 0) && data.to === this.kernel) {
19833
+ return this.answered(data);
19834
+ }
19835
+ if (!this.leader || data.from === void 0) return;
19836
+ if (data.adopt) return this.adopt(data.from, data.adopt);
19837
+ if (data.cancel !== void 0) return void this.waiting.get(data.cancel)?.abort();
19838
+ if (data.ask && data.id !== void 0) await this.request(data.from, data.id, data.ask);
19839
+ }
19840
+ answered(data) {
19841
+ const p = this.pending.get(data.id);
19842
+ if (!p) return;
19843
+ this.pending.delete(data.id);
19844
+ if (data.errno !== void 0) p.reject(new KernelError(data.errno));
19845
+ else p.resolve(data.ok);
19846
+ }
19847
+ async request(from, id2, ask) {
19848
+ const known = this.granted.get(id2);
19849
+ if (known) return void this.channel.postMessage({ id: id2, to: from, ...known });
19850
+ await this.settled;
19851
+ let reply;
19852
+ try {
19853
+ reply = { ok: await this.serve(ask, from, id2) ?? null };
19854
+ } catch (err) {
19855
+ reply = { errno: err.code ?? "EIO" };
19856
+ }
19857
+ this.granted.set(id2, reply);
19858
+ if (this.granted.size > 4096) this.granted.delete(this.granted.keys().next().value);
19859
+ this.channel.postMessage({ id: id2, to: from, ...reply });
19860
+ }
19861
+ ownerFor(kernel, owner) {
19862
+ if (kernel === this.kernel) return owner;
19863
+ const name2 = `${kernel}:${owner}`;
19864
+ let id2 = this.owners.get(name2);
19865
+ if (id2 === void 0) {
19866
+ id2 = this.nextRemote--;
19867
+ this.owners.set(name2, id2);
19868
+ this.ownerOf.set(id2, { kernel, owner });
19869
+ this.watchRemotes();
19870
+ }
19871
+ return id2;
19872
+ }
19873
+ tokenFor(kernel, owner) {
19874
+ if (kernel === this.kernel) return this.flockOwners.get(owner) ?? {};
19875
+ const name2 = `${kernel}:${owner}`;
19876
+ let token = this.tokens.get(name2);
19877
+ if (!token) {
19878
+ token = { kernel, owner };
19879
+ this.tokens.set(name2, token);
19880
+ this.watchRemotes();
19881
+ }
19882
+ return token;
19883
+ }
19884
+ async serve(ask, from, id2) {
19885
+ const t = this.table;
19886
+ switch (ask.op) {
19887
+ case "set":
19888
+ return t.set(ask.key, this.ownerFor(from, ask.owner), ask.kind, ask.start, ask.end);
19889
+ case "holder": {
19890
+ const held = t.holder(ask.key, this.ownerFor(from, ask.owner), ask);
19891
+ if (!held) return void 0;
19892
+ return { ...held, owner: this.ownerOf.get(held.owner)?.owner ?? held.owner };
19893
+ }
19894
+ case "wait":
19895
+ return this.blockFor(
19896
+ id2,
19897
+ () => t.wait(ask.key, this.ownerFor(from, ask.owner), ask.kind, ask, () => this.signalOf(id2))
19898
+ );
19899
+ case "drop":
19900
+ return t.dropFile(ask.key, this.ownerFor(from, ask.owner));
19901
+ case "release":
19902
+ return t.release(this.ownerFor(from, ask.owner));
19903
+ case "fset":
19904
+ return t.flocks.set(ask.key, this.tokenFor(from, ask.owner), ask.kind);
19905
+ case "fwait":
19906
+ return this.blockFor(
19907
+ id2,
19908
+ () => t.flocks.wait(ask.key, this.tokenFor(from, ask.owner), ask.kind, () => this.signalOf(id2))
19909
+ );
19910
+ case "fdrop":
19911
+ return t.flocks.drop(this.tokenFor(from, ask.owner));
19912
+ }
19913
+ }
19914
+ signalOf(id2) {
19915
+ if (id2 === void 0) return new AbortController().signal;
19916
+ let c = this.waiting.get(id2);
19917
+ if (!c) {
19918
+ c = new AbortController();
19919
+ this.waiting.set(id2, c);
19920
+ }
19921
+ return c.signal;
19922
+ }
19923
+ async blockFor(id2, run2) {
19924
+ try {
19925
+ await run2();
19926
+ } finally {
19927
+ if (id2 !== void 0) this.waiting.delete(id2);
19928
+ }
19929
+ }
19930
+ watchRemotes() {
19931
+ if (this.pruner || this.ownerOf.size === 0 && this.tokens.size === 0) return;
19932
+ this.pruner = setInterval(() => void this.prune(), PRUNE_MS);
19933
+ this.pruner.unref?.();
19934
+ }
19935
+ async prune() {
19936
+ const held = new Set(((await this.locks.query()).held ?? []).map((l) => l.name));
19937
+ for (const [id2, { kernel, owner }] of [...this.ownerOf]) {
19938
+ if (held.has(this.aliveOf(kernel))) continue;
19939
+ this.table.release(id2);
19940
+ this.ownerOf.delete(id2);
19941
+ this.owners.delete(`${kernel}:${owner}`);
19942
+ }
19943
+ for (const [name2, token] of [...this.tokens]) {
19944
+ if (held.has(this.aliveOf(name2.slice(0, name2.lastIndexOf(":"))))) continue;
19945
+ this.table.flocks.drop(token);
19946
+ this.tokens.delete(name2);
19947
+ }
19948
+ if (this.pruner && this.ownerOf.size === 0 && this.tokens.size === 0) {
19949
+ clearInterval(this.pruner);
19950
+ this.pruner = void 0;
19951
+ }
19952
+ }
19953
+ reassert() {
19954
+ const records = this.table.entries();
19955
+ const flocks = this.table.flocks.entries().map(([key, owner, kind]) => [key, this.flockIdOf(owner), kind]);
19956
+ this.channel.postMessage({ adopt: { records, flocks }, from: this.kernel });
19957
+ for (const [id2, p] of this.pending)
19958
+ this.channel.postMessage({ id: id2, from: this.kernel, ask: p.ask });
19959
+ }
19960
+ adopt(from, held) {
19961
+ for (const [key, locks] of held.records)
19962
+ for (const l of locks)
19963
+ this.table.set(key, this.ownerFor(from, l.owner), l.kind, l.start, l.end);
19964
+ for (const [key, owner, kind] of held.flocks)
19965
+ this.table.flocks.set(key, this.tokenFor(from, owner), kind);
19966
+ }
19967
+ flockIdOf(owner) {
19968
+ let id2 = this.flockIds.get(owner);
19969
+ if (id2 === void 0) {
19970
+ id2 = this.nextFlock++;
19971
+ this.flockIds.set(owner, id2);
19972
+ this.flockOwners.set(id2, owner);
19973
+ }
19974
+ return id2;
19975
+ }
19976
+ async ask(ask, signal) {
19977
+ await this.role;
19978
+ await this.settled;
19979
+ if (this.leader) return this.serve(ask, this.kernel);
19980
+ const id2 = `${this.kernel}:${this.next++}`;
19981
+ return new Promise((resolve2, reject) => {
19982
+ this.pending.set(id2, { ask, resolve: resolve2, reject });
19983
+ this.channel.postMessage({ id: id2, from: this.kernel, ask });
19984
+ signal?.addEventListener(
19985
+ "abort",
19986
+ () => {
19987
+ if (!this.pending.delete(id2)) return;
19988
+ this.channel.postMessage({ cancel: id2, from: this.kernel });
19989
+ reject(new KernelError("EINTR"));
19990
+ },
19991
+ { once: true }
19992
+ );
19993
+ });
19994
+ }
19995
+ async holder(key, owner, want) {
19996
+ return await this.ask({
19997
+ op: "holder",
19998
+ key,
19999
+ owner,
20000
+ kind: want.kind,
20001
+ start: want.start,
20002
+ end: want.end
20003
+ }) ?? void 0;
20004
+ }
20005
+ async set(key, owner, kind, start2, end) {
20006
+ const ok4 = await this.ask({ op: "set", key, owner, kind, start: start2, end }) === true;
20007
+ if (ok4 && !this.leader) this.table.set(key, owner, kind, start2, end);
20008
+ return ok4;
20009
+ }
20010
+ async wait(key, owner, kind, range2, blocking) {
20011
+ await this.role;
20012
+ await this.settled;
20013
+ if (this.leader) return this.table.wait(key, owner, kind, range2, blocking);
20014
+ if (await this.set(key, owner, kind, range2.start, range2.end)) return;
20015
+ await this.ask({ op: "wait", key, owner, kind, ...range2 }, blocking());
20016
+ if (!this.leader) this.table.set(key, owner, kind, range2.start, range2.end);
20017
+ }
20018
+ holds(owner) {
20019
+ return this.table.holds(owner);
20020
+ }
20021
+ dropFile(key, owner) {
20022
+ if (!this.leader) this.table.dropFile(key, owner);
20023
+ void this.ask({ op: "drop", key, owner }).catch(() => void 0);
20024
+ }
20025
+ release(pid) {
20026
+ if (!this.leader) this.table.release(pid);
20027
+ void this.ask({ op: "release", owner: pid }).catch(() => void 0);
20028
+ }
20029
+ async flockSet(key, owner, kind) {
20030
+ await this.role;
20031
+ await this.settled;
20032
+ if (this.leader) return this.table.flocks.set(key, owner, kind);
20033
+ const ok4 = await this.ask({ op: "fset", key, owner: this.flockIdOf(owner), kind }) === true;
20034
+ if (ok4) this.table.flocks.set(key, owner, kind);
20035
+ return ok4;
20036
+ }
20037
+ async flockWait(key, owner, kind, blocking) {
20038
+ await this.role;
20039
+ await this.settled;
20040
+ if (this.leader) return this.table.flocks.wait(key, owner, kind, blocking);
20041
+ if (await this.flockSet(key, owner, kind)) return;
20042
+ await this.ask({ op: "fwait", key, owner: this.flockIdOf(owner), kind }, blocking());
20043
+ if (!this.leader) this.table.flocks.set(key, owner, kind);
20044
+ }
20045
+ flockDrop(owner) {
20046
+ if (!this.leader) this.table.flocks.drop(owner);
20047
+ void this.ask({ op: "fdrop", owner: this.flockIdOf(owner) }).catch(() => void 0);
20048
+ }
20049
+ lock(pid, path, exclusive, fd) {
20050
+ return this.table.lock(pid, path, exclusive, fd);
20051
+ }
20052
+ unlock(pid, path) {
20053
+ this.table.unlock(pid, path);
20054
+ }
20055
+ closed(pid, fd) {
20056
+ this.table.closed(pid, fd);
20057
+ }
20058
+ };
20059
+ function kernelLocks(root) {
20060
+ const locks = globalThis.navigator?.locks;
20061
+ if (root === void 0 || !locks || typeof BroadcastChannel !== "function")
20062
+ return new LockTable();
20063
+ return new LockService({ root, locks });
20064
+ }
20065
+ var ASK_OPS = /* @__PURE__ */ new Set([
20066
+ "set",
20067
+ "wait",
20068
+ "holder",
20069
+ "drop",
20070
+ "release",
20071
+ "fset",
20072
+ "fwait",
20073
+ "fdrop"
20074
+ ]);
20075
+ function askOk(ask) {
20076
+ if (typeof ask !== "object" || ask === null) return false;
20077
+ const a = ask;
20078
+ if (!ASK_OPS.has(String(a.op)) || typeof a.owner !== "number") return false;
20079
+ return a.key === void 0 || typeof a.key === "string";
20080
+ }
20081
+ function isMessage(data) {
20082
+ if (typeof data !== "object" || data === null || Array.isArray(data)) return false;
20083
+ const m = data;
20084
+ for (const field4 of ["id", "from", "to", "cancel", "errno"])
20085
+ if (m[field4] !== void 0 && typeof m[field4] !== "string") return false;
20086
+ if (m.ask !== void 0 && !askOk(m.ask)) return false;
20087
+ const adopt = m.adopt;
20088
+ if (adopt === void 0) return true;
20089
+ return adopt !== null && Array.isArray(adopt.records) && Array.isArray(adopt.flocks);
20090
+ }
20091
+
19743
20092
  // src/kernel/net/hosts-file.ts
19744
20093
  var HOSTS_PATH = "/etc/hosts";
19745
20094
  function parseHosts(text) {
@@ -23111,7 +23460,7 @@ var Launcher = class {
23111
23460
  users;
23112
23461
  sudoer;
23113
23462
  jobs = new JobTable();
23114
- locks = new LockTable();
23463
+ locks;
23115
23464
  fifos = new FifoTable();
23116
23465
  sems = new SemTable();
23117
23466
  settling = new SettlingChildren((pid) => this.jobs.pgidOf(pid));
@@ -23167,6 +23516,7 @@ var Launcher = class {
23167
23516
  constructor(options) {
23168
23517
  this.usersMode = usersMode(options.users);
23169
23518
  this.rootFs = options.fs;
23519
+ this.locks = kernelLocks(options.fs.rootName);
23170
23520
  this.dac = this.usersMode === "off" ? void 0 : new Dac(this.usersMode, options.onDenial);
23171
23521
  if (this.dac) this.dac.tagOf = (pid) => this.tagOf(pid);
23172
23522
  this.clipboard = new ClipboardBroker(