@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.
@@ -1183,12 +1183,14 @@ var OpfsFs = class {
1183
1183
  mounts = {};
1184
1184
  locks;
1185
1185
  lockPrefix;
1186
+ rootName;
1186
1187
  constructor(root, meta = new MemoryMeta(), channel, options = {}) {
1187
1188
  this.root = root;
1188
1189
  this.meta = sidecar(meta);
1189
1190
  this.ranged = options.ranged === true;
1190
1191
  this.locks = options.locks === void 0 ? lockManager() : options.locks ?? void 0;
1191
1192
  this.lockPrefix = `slicc-excl:${channel ?? ""}:`;
1193
+ this.rootName = channel;
1192
1194
  this.channel = channel === void 0 ? void 0 : new BroadcastChannel(channel);
1193
1195
  this.remote = channel === void 0 ? void 0 : new RemoteWatch(`${channel}:watch`);
1194
1196
  if (this.remote) this.remote.quiet = () => this.quiet();
@@ -6364,7 +6366,7 @@ function satisfies(version, range2) {
6364
6366
  }
6365
6367
 
6366
6368
  // src/version.ts
6367
- var KERNEL_VERSION = true ? "1.118.1" : "0.0.0-dev";
6369
+ var KERNEL_VERSION = true ? "1.119.1" : "0.0.0-dev";
6368
6370
  var OS_RELEASE = "6.0.0-slicc";
6369
6371
  function procVersion() {
6370
6372
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -13302,6 +13304,12 @@ var FlockTable = class {
13302
13304
  await changedAt(this.wakers, key, signal);
13303
13305
  }
13304
13306
  }
13307
+ entries() {
13308
+ const out = [];
13309
+ for (const [key, holders] of this.held)
13310
+ for (const [owner, kind] of holders) out.push([key, owner, kind]);
13311
+ return out;
13312
+ }
13305
13313
  drop(owner) {
13306
13314
  const key = this.keys.get(owner);
13307
13315
  if (key === void 0) return;
@@ -13380,6 +13388,9 @@ var LockTable = class {
13380
13388
  if (locks.length === 0) this.records.delete(key);
13381
13389
  else this.records.set(key, locks);
13382
13390
  }
13391
+ entries() {
13392
+ return [...this.records].map(([key, locks]) => [key, locks.map((l) => ({ ...l }))]);
13393
+ }
13383
13394
  holds(owner) {
13384
13395
  for (const locks of this.records.values())
13385
13396
  if (locks.some((l) => l.owner === owner)) return true;
@@ -13624,7 +13635,7 @@ async function flock(req, ctx) {
13624
13635
  const { key, owner } = await flockOf(req.fd);
13625
13636
  if (req.kind !== "unlock" && req.wait)
13626
13637
  await locks.flocks.wait(key, owner, req.kind, ctx.blocking);
13627
- else if (!locks.flocks.set(key, owner, req.kind)) throw new KernelError("EAGAIN");
13638
+ else if (!await locks.flocks.set(key, owner, req.kind)) throw new KernelError("EAGAIN");
13628
13639
  return done2;
13629
13640
  }
13630
13641
  async function recordLock2(req, ctx) {
@@ -13642,7 +13653,7 @@ async function recordLock2(req, ctx) {
13642
13653
  const range2 = lockRange(req.start, req.len);
13643
13654
  const key = await fileKey(target, req.kind, req.op === "lk-set" && req.fd !== void 0);
13644
13655
  if (req.op === "lk-get") {
13645
- const held = locks.holder(key, owner, { key, kind: req.kind, ...range2 });
13656
+ const held = await locks.holder(key, owner, { key, kind: req.kind, ...range2 });
13646
13657
  if (!held) return json3(null);
13647
13658
  const len = held.end === Number.POSITIVE_INFINITY ? 0 : held.end - held.start;
13648
13659
  return json3({ kind: held.kind, pid: held.owner, start: held.start, len });
@@ -13651,7 +13662,8 @@ async function recordLock2(req, ctx) {
13651
13662
  await locks.wait(key, owner, req.kind, range2, ctx.blocking);
13652
13663
  return done2;
13653
13664
  }
13654
- if (!locks.set(key, owner, req.kind, range2.start, range2.end)) throw new KernelError("EAGAIN");
13665
+ if (!await locks.set(key, owner, req.kind, range2.start, range2.end))
13666
+ throw new KernelError("EAGAIN");
13655
13667
  return done2;
13656
13668
  }
13657
13669
 
@@ -19802,6 +19814,343 @@ var JobTable = class {
19802
19814
  }
19803
19815
  };
19804
19816
 
19817
+ // src/kernel/lock-service.ts
19818
+ var PRUNE_MS = 1e3;
19819
+ var LOCKS_PROTOCOL = "v1";
19820
+ var LockService = class {
19821
+ kernel = crypto.randomUUID();
19822
+ table = new LockTable();
19823
+ leader = false;
19824
+ role;
19825
+ channel;
19826
+ locks;
19827
+ root;
19828
+ pending = /* @__PURE__ */ new Map();
19829
+ next = 0;
19830
+ owners = /* @__PURE__ */ new Map();
19831
+ ownerOf = /* @__PURE__ */ new Map();
19832
+ nextRemote = -1;
19833
+ tokens = /* @__PURE__ */ new Map();
19834
+ flockIds = /* @__PURE__ */ new WeakMap();
19835
+ flockOwners = /* @__PURE__ */ new Map();
19836
+ nextFlock = 1;
19837
+ granted = /* @__PURE__ */ new Map();
19838
+ waiting = /* @__PURE__ */ new Map();
19839
+ settled = Promise.resolve();
19840
+ pruner;
19841
+ flocks;
19842
+ constructor(options) {
19843
+ this.root = options.root;
19844
+ this.locks = options.locks;
19845
+ this.channel = (options.channel ?? ((n) => new BroadcastChannel(n)))(
19846
+ `slicc-locks:${LOCKS_PROTOCOL}:${this.root}`
19847
+ );
19848
+ this.channel.unref?.();
19849
+ this.channel.onmessage = ({ data }) => {
19850
+ if (isMessage(data)) void this.receive(data);
19851
+ };
19852
+ void this.locks.request(this.aliveOf(this.kernel), () => new Promise(() => {
19853
+ }));
19854
+ this.role = this.elect();
19855
+ this.flocks = {
19856
+ set: (key, owner, kind) => this.flockSet(key, owner, kind),
19857
+ wait: (key, owner, kind, blocking) => this.flockWait(key, owner, kind, blocking),
19858
+ drop: (owner) => this.flockDrop(owner)
19859
+ };
19860
+ }
19861
+ aliveOf(kernel) {
19862
+ return `slicc-locks-alive:${LOCKS_PROTOCOL}:${this.root}:${kernel}`;
19863
+ }
19864
+ elect() {
19865
+ const name2 = `slicc-locks-leader:${LOCKS_PROTOCOL}:${this.root}`;
19866
+ return new Promise((decided) => {
19867
+ void this.locks.request(name2, { ifAvailable: true }, async (lock) => {
19868
+ this.leader = lock !== null;
19869
+ decided();
19870
+ if (this.leader) await new Promise(() => {
19871
+ });
19872
+ });
19873
+ }).then(() => {
19874
+ if (this.leader) return;
19875
+ void this.locks.request(name2, async () => {
19876
+ await this.lead();
19877
+ await new Promise(() => {
19878
+ });
19879
+ });
19880
+ });
19881
+ }
19882
+ async lead() {
19883
+ this.leader = true;
19884
+ this.settled = new Promise((resolve2) => setTimeout(resolve2, ANNOUNCE_WAIT_MS));
19885
+ this.channel.postMessage({ reassert: true, from: this.kernel });
19886
+ const pending = [...this.pending.entries()];
19887
+ this.pending.clear();
19888
+ await this.settled;
19889
+ for (const [, p] of pending) void this.serve(p.ask, this.kernel).then(p.resolve, p.reject);
19890
+ }
19891
+ async receive(data) {
19892
+ if (data.reassert && data.from !== this.kernel) return this.reassert();
19893
+ if (data.to !== void 0 && data.to !== this.kernel) return;
19894
+ if (data.id !== void 0 && (data.ok !== void 0 || data.errno !== void 0) && data.to === this.kernel) {
19895
+ return this.answered(data);
19896
+ }
19897
+ if (!this.leader || data.from === void 0) return;
19898
+ if (data.adopt) return this.adopt(data.from, data.adopt);
19899
+ if (data.cancel !== void 0) return void this.waiting.get(data.cancel)?.abort();
19900
+ if (data.ask && data.id !== void 0) await this.request(data.from, data.id, data.ask);
19901
+ }
19902
+ answered(data) {
19903
+ const p = this.pending.get(data.id);
19904
+ if (!p) return;
19905
+ this.pending.delete(data.id);
19906
+ if (data.errno !== void 0) p.reject(new KernelError(data.errno));
19907
+ else p.resolve(data.ok);
19908
+ }
19909
+ async request(from, id2, ask) {
19910
+ const known = this.granted.get(id2);
19911
+ if (known) return void this.channel.postMessage({ id: id2, to: from, ...known });
19912
+ await this.settled;
19913
+ let reply;
19914
+ try {
19915
+ reply = { ok: await this.serve(ask, from, id2) ?? null };
19916
+ } catch (err) {
19917
+ reply = { errno: err.code ?? "EIO" };
19918
+ }
19919
+ this.granted.set(id2, reply);
19920
+ if (this.granted.size > 4096) this.granted.delete(this.granted.keys().next().value);
19921
+ this.channel.postMessage({ id: id2, to: from, ...reply });
19922
+ }
19923
+ ownerFor(kernel, owner) {
19924
+ if (kernel === this.kernel) return owner;
19925
+ const name2 = `${kernel}:${owner}`;
19926
+ let id2 = this.owners.get(name2);
19927
+ if (id2 === void 0) {
19928
+ id2 = this.nextRemote--;
19929
+ this.owners.set(name2, id2);
19930
+ this.ownerOf.set(id2, { kernel, owner });
19931
+ this.watchRemotes();
19932
+ }
19933
+ return id2;
19934
+ }
19935
+ tokenFor(kernel, owner) {
19936
+ if (kernel === this.kernel) return this.flockOwners.get(owner) ?? {};
19937
+ const name2 = `${kernel}:${owner}`;
19938
+ let token = this.tokens.get(name2);
19939
+ if (!token) {
19940
+ token = { kernel, owner };
19941
+ this.tokens.set(name2, token);
19942
+ this.watchRemotes();
19943
+ }
19944
+ return token;
19945
+ }
19946
+ async serve(ask, from, id2) {
19947
+ const t = this.table;
19948
+ switch (ask.op) {
19949
+ case "set":
19950
+ return t.set(ask.key, this.ownerFor(from, ask.owner), ask.kind, ask.start, ask.end);
19951
+ case "holder": {
19952
+ const held = t.holder(ask.key, this.ownerFor(from, ask.owner), ask);
19953
+ if (!held) return void 0;
19954
+ return { ...held, owner: this.ownerOf.get(held.owner)?.owner ?? held.owner };
19955
+ }
19956
+ case "wait":
19957
+ return this.blockFor(
19958
+ id2,
19959
+ () => t.wait(ask.key, this.ownerFor(from, ask.owner), ask.kind, ask, () => this.signalOf(id2))
19960
+ );
19961
+ case "drop":
19962
+ return t.dropFile(ask.key, this.ownerFor(from, ask.owner));
19963
+ case "release":
19964
+ return t.release(this.ownerFor(from, ask.owner));
19965
+ case "fset":
19966
+ return t.flocks.set(ask.key, this.tokenFor(from, ask.owner), ask.kind);
19967
+ case "fwait":
19968
+ return this.blockFor(
19969
+ id2,
19970
+ () => t.flocks.wait(ask.key, this.tokenFor(from, ask.owner), ask.kind, () => this.signalOf(id2))
19971
+ );
19972
+ case "fdrop":
19973
+ return t.flocks.drop(this.tokenFor(from, ask.owner));
19974
+ }
19975
+ }
19976
+ signalOf(id2) {
19977
+ if (id2 === void 0) return new AbortController().signal;
19978
+ let c = this.waiting.get(id2);
19979
+ if (!c) {
19980
+ c = new AbortController();
19981
+ this.waiting.set(id2, c);
19982
+ }
19983
+ return c.signal;
19984
+ }
19985
+ async blockFor(id2, run2) {
19986
+ try {
19987
+ await run2();
19988
+ } finally {
19989
+ if (id2 !== void 0) this.waiting.delete(id2);
19990
+ }
19991
+ }
19992
+ watchRemotes() {
19993
+ if (this.pruner || this.ownerOf.size === 0 && this.tokens.size === 0) return;
19994
+ this.pruner = setInterval(() => void this.prune(), PRUNE_MS);
19995
+ this.pruner.unref?.();
19996
+ }
19997
+ async prune() {
19998
+ const held = new Set(((await this.locks.query()).held ?? []).map((l) => l.name));
19999
+ for (const [id2, { kernel, owner }] of [...this.ownerOf]) {
20000
+ if (held.has(this.aliveOf(kernel))) continue;
20001
+ this.table.release(id2);
20002
+ this.ownerOf.delete(id2);
20003
+ this.owners.delete(`${kernel}:${owner}`);
20004
+ }
20005
+ for (const [name2, token] of [...this.tokens]) {
20006
+ if (held.has(this.aliveOf(name2.slice(0, name2.lastIndexOf(":"))))) continue;
20007
+ this.table.flocks.drop(token);
20008
+ this.tokens.delete(name2);
20009
+ }
20010
+ if (this.pruner && this.ownerOf.size === 0 && this.tokens.size === 0) {
20011
+ clearInterval(this.pruner);
20012
+ this.pruner = void 0;
20013
+ }
20014
+ }
20015
+ reassert() {
20016
+ const records = this.table.entries();
20017
+ const flocks = this.table.flocks.entries().map(([key, owner, kind]) => [key, this.flockIdOf(owner), kind]);
20018
+ this.channel.postMessage({ adopt: { records, flocks }, from: this.kernel });
20019
+ for (const [id2, p] of this.pending)
20020
+ this.channel.postMessage({ id: id2, from: this.kernel, ask: p.ask });
20021
+ }
20022
+ adopt(from, held) {
20023
+ for (const [key, locks] of held.records)
20024
+ for (const l of locks)
20025
+ this.table.set(key, this.ownerFor(from, l.owner), l.kind, l.start, l.end);
20026
+ for (const [key, owner, kind] of held.flocks)
20027
+ this.table.flocks.set(key, this.tokenFor(from, owner), kind);
20028
+ }
20029
+ flockIdOf(owner) {
20030
+ let id2 = this.flockIds.get(owner);
20031
+ if (id2 === void 0) {
20032
+ id2 = this.nextFlock++;
20033
+ this.flockIds.set(owner, id2);
20034
+ this.flockOwners.set(id2, owner);
20035
+ }
20036
+ return id2;
20037
+ }
20038
+ async ask(ask, signal) {
20039
+ await this.role;
20040
+ await this.settled;
20041
+ if (this.leader) return this.serve(ask, this.kernel);
20042
+ const id2 = `${this.kernel}:${this.next++}`;
20043
+ return new Promise((resolve2, reject) => {
20044
+ this.pending.set(id2, { ask, resolve: resolve2, reject });
20045
+ this.channel.postMessage({ id: id2, from: this.kernel, ask });
20046
+ signal?.addEventListener(
20047
+ "abort",
20048
+ () => {
20049
+ if (!this.pending.delete(id2)) return;
20050
+ this.channel.postMessage({ cancel: id2, from: this.kernel });
20051
+ reject(new KernelError("EINTR"));
20052
+ },
20053
+ { once: true }
20054
+ );
20055
+ });
20056
+ }
20057
+ async holder(key, owner, want) {
20058
+ return await this.ask({
20059
+ op: "holder",
20060
+ key,
20061
+ owner,
20062
+ kind: want.kind,
20063
+ start: want.start,
20064
+ end: want.end
20065
+ }) ?? void 0;
20066
+ }
20067
+ async set(key, owner, kind, start2, end) {
20068
+ const ok4 = await this.ask({ op: "set", key, owner, kind, start: start2, end }) === true;
20069
+ if (ok4 && !this.leader) this.table.set(key, owner, kind, start2, end);
20070
+ return ok4;
20071
+ }
20072
+ async wait(key, owner, kind, range2, blocking) {
20073
+ await this.role;
20074
+ await this.settled;
20075
+ if (this.leader) return this.table.wait(key, owner, kind, range2, blocking);
20076
+ if (await this.set(key, owner, kind, range2.start, range2.end)) return;
20077
+ await this.ask({ op: "wait", key, owner, kind, ...range2 }, blocking());
20078
+ if (!this.leader) this.table.set(key, owner, kind, range2.start, range2.end);
20079
+ }
20080
+ holds(owner) {
20081
+ return this.table.holds(owner);
20082
+ }
20083
+ dropFile(key, owner) {
20084
+ if (!this.leader) this.table.dropFile(key, owner);
20085
+ void this.ask({ op: "drop", key, owner }).catch(() => void 0);
20086
+ }
20087
+ release(pid) {
20088
+ if (!this.leader) this.table.release(pid);
20089
+ void this.ask({ op: "release", owner: pid }).catch(() => void 0);
20090
+ }
20091
+ async flockSet(key, owner, kind) {
20092
+ await this.role;
20093
+ await this.settled;
20094
+ if (this.leader) return this.table.flocks.set(key, owner, kind);
20095
+ const ok4 = await this.ask({ op: "fset", key, owner: this.flockIdOf(owner), kind }) === true;
20096
+ if (ok4) this.table.flocks.set(key, owner, kind);
20097
+ return ok4;
20098
+ }
20099
+ async flockWait(key, owner, kind, blocking) {
20100
+ await this.role;
20101
+ await this.settled;
20102
+ if (this.leader) return this.table.flocks.wait(key, owner, kind, blocking);
20103
+ if (await this.flockSet(key, owner, kind)) return;
20104
+ await this.ask({ op: "fwait", key, owner: this.flockIdOf(owner), kind }, blocking());
20105
+ if (!this.leader) this.table.flocks.set(key, owner, kind);
20106
+ }
20107
+ flockDrop(owner) {
20108
+ if (!this.leader) this.table.flocks.drop(owner);
20109
+ void this.ask({ op: "fdrop", owner: this.flockIdOf(owner) }).catch(() => void 0);
20110
+ }
20111
+ lock(pid, path, exclusive, fd) {
20112
+ return this.table.lock(pid, path, exclusive, fd);
20113
+ }
20114
+ unlock(pid, path) {
20115
+ this.table.unlock(pid, path);
20116
+ }
20117
+ closed(pid, fd) {
20118
+ this.table.closed(pid, fd);
20119
+ }
20120
+ };
20121
+ function kernelLocks(root) {
20122
+ const locks = globalThis.navigator?.locks;
20123
+ if (root === void 0 || !locks || typeof BroadcastChannel !== "function")
20124
+ return new LockTable();
20125
+ return new LockService({ root, locks });
20126
+ }
20127
+ var ASK_OPS = /* @__PURE__ */ new Set([
20128
+ "set",
20129
+ "wait",
20130
+ "holder",
20131
+ "drop",
20132
+ "release",
20133
+ "fset",
20134
+ "fwait",
20135
+ "fdrop"
20136
+ ]);
20137
+ function askOk(ask) {
20138
+ if (typeof ask !== "object" || ask === null) return false;
20139
+ const a = ask;
20140
+ if (!ASK_OPS.has(String(a.op)) || typeof a.owner !== "number") return false;
20141
+ return a.key === void 0 || typeof a.key === "string";
20142
+ }
20143
+ function isMessage(data) {
20144
+ if (typeof data !== "object" || data === null || Array.isArray(data)) return false;
20145
+ const m = data;
20146
+ for (const field4 of ["id", "from", "to", "cancel", "errno"])
20147
+ if (m[field4] !== void 0 && typeof m[field4] !== "string") return false;
20148
+ if (m.ask !== void 0 && !askOk(m.ask)) return false;
20149
+ const adopt = m.adopt;
20150
+ if (adopt === void 0) return true;
20151
+ return adopt !== null && Array.isArray(adopt.records) && Array.isArray(adopt.flocks);
20152
+ }
20153
+
19805
20154
  // src/kernel/net/hosts-file.ts
19806
20155
  var HOSTS_PATH = "/etc/hosts";
19807
20156
  function parseHosts(text) {
@@ -23105,7 +23454,7 @@ var Launcher = class {
23105
23454
  users;
23106
23455
  sudoer;
23107
23456
  jobs = new JobTable();
23108
- locks = new LockTable();
23457
+ locks;
23109
23458
  fifos = new FifoTable();
23110
23459
  sems = new SemTable();
23111
23460
  settling = new SettlingChildren((pid) => this.jobs.pgidOf(pid));
@@ -23161,6 +23510,7 @@ var Launcher = class {
23161
23510
  constructor(options) {
23162
23511
  this.usersMode = usersMode(options.users);
23163
23512
  this.rootFs = options.fs;
23513
+ this.locks = kernelLocks(options.fs.rootName);
23164
23514
  this.dac = this.usersMode === "off" ? void 0 : new Dac(this.usersMode, options.onDenial);
23165
23515
  if (this.dac) this.dac.tagOf = (pid) => this.tagOf(pid);
23166
23516
  this.clipboard = new ClipboardBroker(