@ai-ecoverse/slicc-kernel 1.124.6 → 1.124.8

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
@@ -5776,6 +5776,7 @@ var LOOKUP_OPS = [
5776
5776
  "realpath"
5777
5777
  ];
5778
5778
  var within4 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
5779
+ var TOUCHED_MAX = 4096;
5779
5780
  var parentOf5 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
5780
5781
  var lockName = (instance) => `slicc-unlinked:${instance}`;
5781
5782
  var dirOf = (root) => root === "/" ? `/${UNLINKED_DIR}` : `${root}/${UNLINKED_DIR}`;
@@ -5814,6 +5815,9 @@ var UnlinkedKeeper = class {
5814
5815
  queue = Promise.resolve();
5815
5816
  count = 0;
5816
5817
  replacing = /* @__PURE__ */ new Map();
5818
+ gen = 0;
5819
+ floor = 0;
5820
+ touched = /* @__PURE__ */ new Map();
5817
5821
  replaced = 0;
5818
5822
  links = /* @__PURE__ */ new Map();
5819
5823
  linked = /* @__PURE__ */ new Map();
@@ -5840,28 +5844,28 @@ var UnlinkedKeeper = class {
5840
5844
  const { replacing } = this;
5841
5845
  const replace = async (target, op) => {
5842
5846
  const { promise, resolve: resolve2 } = Promise.withResolvers();
5847
+ keeper.touch(target);
5843
5848
  let mine;
5844
5849
  const gated = () => {
5845
5850
  const before = replacing.get(target);
5846
- mine = { done: Promise.all([before?.done, promise]).then(() => void 0) };
5851
+ mine = { done: Promise.all([before?.done, promise]).then(() => void 0), sealed: false };
5847
5852
  replacing.set(target, mine);
5848
5853
  };
5854
+ const sealed = () => {
5855
+ if (mine) mine.sealed = true;
5856
+ };
5849
5857
  try {
5850
- await op(gated);
5858
+ await op(gated, sealed);
5851
5859
  } finally {
5852
5860
  keeper.replaced += 1;
5861
+ keeper.touch(target);
5853
5862
  resolve2();
5854
5863
  if (mine && replacing.get(target) === mine) replacing.delete(target);
5855
5864
  }
5856
5865
  };
5857
5866
  const unreplaced = async (path, op) => {
5858
5867
  const at = fs.resolvePath("/", path);
5859
- const pending = async () => {
5860
- for (let p = at; replacing.size > 0; p = parentOf5(p)) {
5861
- await replacing.get(p)?.done;
5862
- if (p === "/") return;
5863
- }
5864
- };
5868
+ const pending = () => keeper.settled(at);
5865
5869
  for (let attempt = 1; ; attempt++) {
5866
5870
  await pending();
5867
5871
  const seen = keeper.replaced;
@@ -5895,8 +5899,8 @@ var UnlinkedKeeper = class {
5895
5899
  lstat: (path) => unreplaced(path, async () => counted3(await fs.lstat(path))),
5896
5900
  async rm(path, options) {
5897
5901
  const target = fs.resolvePath("/", path);
5898
- await replace(target, async (gated) => {
5899
- const pinned = await keeper.pin(target, gated);
5902
+ await replace(target, async (gated, sealed) => {
5903
+ const pinned = await keeper.pin(target, gated, sealed);
5900
5904
  if (pinned.moved.has(target)) pinned.commit();
5901
5905
  else await keeper.settle(pinned, () => fs.rm(path, options));
5902
5906
  });
@@ -5904,8 +5908,8 @@ var UnlinkedKeeper = class {
5904
5908
  async rename(from, to) {
5905
5909
  const target = fs.resolvePath("/", to);
5906
5910
  if (target === fs.resolvePath("/", from)) return fs.rename(from, to);
5907
- await replace(target, async (gated) => {
5908
- const pinned = await keeper.pin(target, gated);
5911
+ await replace(target, async (gated, sealed) => {
5912
+ const pinned = await keeper.pin(target, gated, sealed);
5909
5913
  await keeper.settle(pinned, () => fs.rename(from, to));
5910
5914
  });
5911
5915
  },
@@ -5913,6 +5917,39 @@ var UnlinkedKeeper = class {
5913
5917
  readdirStat: async (path) => (await fs.readdirStat(path)).filter(([name2]) => name2 !== UNLINKED_DIR).map(([name2, st]) => [name2, st && counted3(st)])
5914
5918
  };
5915
5919
  }
5920
+ async settled(path) {
5921
+ for (let p = path; this.replacing.size > 0; p = parentOf5(p)) {
5922
+ await this.replacing.get(p)?.done;
5923
+ if (p === "/") return;
5924
+ }
5925
+ }
5926
+ generation() {
5927
+ return this.gen;
5928
+ }
5929
+ changedSince(path, gen) {
5930
+ if (gen < this.floor) return true;
5931
+ for (let p = path; this.touched.size > 0; p = parentOf5(p)) {
5932
+ if ((this.touched.get(p) ?? 0) > gen) return true;
5933
+ if (p === "/") return false;
5934
+ }
5935
+ return false;
5936
+ }
5937
+ touch(target) {
5938
+ this.gen += 1;
5939
+ this.touched.delete(target);
5940
+ this.touched.set(target, this.gen);
5941
+ if (this.touched.size <= TOUCHED_MAX) return;
5942
+ const [oldest, at] = this.touched.entries().next().value;
5943
+ this.touched.delete(oldest);
5944
+ this.floor = at;
5945
+ }
5946
+ missed(path) {
5947
+ for (let p = path; this.replacing.size > 0; p = parentOf5(p)) {
5948
+ if (this.replacing.get(p)?.sealed) return true;
5949
+ if (p === "/") return false;
5950
+ }
5951
+ return false;
5952
+ }
5916
5953
  async settle(pinned, op) {
5917
5954
  try {
5918
5955
  await op();
@@ -5933,33 +5970,41 @@ var UnlinkedKeeper = class {
5933
5970
  }
5934
5971
  return held;
5935
5972
  }
5936
- async pin(target, gated = () => void 0) {
5973
+ async pin(target, gated = () => void 0, sealed = () => void 0) {
5937
5974
  const paths = [];
5938
5975
  const releases = [];
5939
- for (; ; ) {
5940
- const fresh2 = [...this.heldWithin(target).keys()].filter((path) => !paths.includes(path));
5941
- if (fresh2.length === 0) break;
5942
- fresh2.sort();
5943
- if (paths.some((path) => path > fresh2[0])) {
5944
- for (const release of releases.splice(0)) release();
5945
- fresh2.push(...paths.splice(0));
5976
+ const take = async () => {
5977
+ for (; ; ) {
5978
+ const fresh2 = [...this.heldWithin(target).keys()].filter((path) => !paths.includes(path));
5979
+ if (fresh2.length === 0) return;
5946
5980
  fresh2.sort();
5981
+ if (paths.some((path) => path > fresh2[0])) {
5982
+ for (const release of releases.splice(0)) release();
5983
+ fresh2.push(...paths.splice(0));
5984
+ fresh2.sort();
5985
+ }
5986
+ for (const path of fresh2) {
5987
+ paths.push(path);
5988
+ releases.push(await this.gate.acquire(path));
5989
+ }
5947
5990
  }
5948
- for (const path of fresh2) {
5949
- paths.push(path);
5950
- releases.push(await this.gate.acquire(path));
5951
- }
5952
- }
5991
+ };
5992
+ await take();
5953
5993
  gated();
5954
- const now = this.heldWithin(target);
5955
- const held = new Map(
5956
- paths.flatMap((path) => now.has(path) ? [[path, now.get(path)]] : [])
5957
- );
5994
+ const held = /* @__PURE__ */ new Map();
5958
5995
  const hidden = /* @__PURE__ */ new Map();
5959
- for (const path of held.keys()) {
5960
- const at = await this.hide(path);
5961
- if (at !== void 0) hidden.set(path, at);
5996
+ for (; ; ) {
5997
+ await take();
5998
+ const now = this.heldWithin(target);
5999
+ const next3 = paths.filter((path) => now.has(path) && !held.has(path));
6000
+ if (next3.length === 0) break;
6001
+ for (const path of next3) {
6002
+ held.set(path, now.get(path));
6003
+ const at = await this.hide(path);
6004
+ if (at !== void 0) hidden.set(path, at);
6005
+ }
5962
6006
  }
6007
+ sealed();
5963
6008
  const done4 = () => {
5964
6009
  for (const release of releases) release();
5965
6010
  };
@@ -7025,7 +7070,7 @@ function satisfies(version, range2) {
7025
7070
  }
7026
7071
 
7027
7072
  // src/version.ts
7028
- var KERNEL_VERSION = true ? "1.124.6" : "0.0.0-dev";
7073
+ var KERNEL_VERSION = true ? "1.124.8" : "0.0.0-dev";
7029
7074
  var OS_RELEASE = "6.0.0-slicc";
7030
7075
  function procVersion() {
7031
7076
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -10409,6 +10454,9 @@ var HeldPaths = class extends Map {
10409
10454
  keptFor(handle) {
10410
10455
  return this.keptHandles.get(handle);
10411
10456
  }
10457
+ holdsHandle(handle) {
10458
+ return this.handles.has(handle);
10459
+ }
10412
10460
  keeps(hidden) {
10413
10461
  for (const file of this.uses.keys()) if (file.hidden === hidden) return true;
10414
10462
  for (const file of this.unlinked.values()) if (file.hidden === hidden) return true;
@@ -11855,10 +11903,16 @@ async function run(entry, path, req) {
11855
11903
  return done;
11856
11904
  case "exists":
11857
11905
  return json2(await fs.exists(path));
11858
- case "stat":
11859
- return json2(statJson(await shownAs(entry, path, await fs.stat(path))));
11860
- case "lstat":
11861
- return json2(statJson(await shownAs(entry, path, await fs.lstat(path))));
11906
+ case "stat": {
11907
+ const gen = entry.replacements?.generation();
11908
+ const st = statJson(await shownAs(entry, path, await fs.stat(path)));
11909
+ return json2(gen === void 0 ? st : { ...st, gen });
11910
+ }
11911
+ case "lstat": {
11912
+ const gen = entry.replacements?.generation();
11913
+ const st = statJson(await shownAs(entry, path, await fs.lstat(path)));
11914
+ return json2(gen === void 0 ? st : { ...st, gen });
11915
+ }
11862
11916
  case "readdir":
11863
11917
  return json2(await fs.readdir(path));
11864
11918
  case "readdir-stat":
@@ -12033,14 +12087,26 @@ async function opening(entry, path, mode) {
12033
12087
  await need(g, "open", path, want, { directory: false });
12034
12088
  }
12035
12089
  }
12090
+ async function stillThere(entry, path, req) {
12091
+ if (req.gen === void 0 || !entry.replacements?.changedSince(path, req.gen)) return;
12092
+ const st = await entry.fs.stat(path).catch(() => void 0);
12093
+ if (!st) throw syncError("ENOENT", path);
12094
+ }
12036
12095
  async function holdOp(entry, path, req) {
12037
12096
  const mode = req.mode ?? 0;
12038
12097
  const [on, open] = [(mode & 1) === 1, (mode & 2) === 2];
12039
12098
  if (on && open) {
12040
- await opening(entry, path, mode);
12041
- const real = await entry.fs.realpath?.(path, true).catch(() => path);
12042
- await entry.source?.open(path, real);
12043
- return json2(entry.hold?.(path, on, open, real) ?? null);
12099
+ for (; ; ) {
12100
+ const r = entry.replacements;
12101
+ await r?.settled(path);
12102
+ const gen = r?.generation() ?? 0;
12103
+ await opening(entry, path, mode);
12104
+ const real = await entry.fs.realpath?.(path, true).catch(() => path);
12105
+ await entry.source?.open(path, real);
12106
+ await stillThere(entry, path, req);
12107
+ if (!r || !r.missed(path) && !r.changedSince(path, gen))
12108
+ return json2(entry.hold?.(path, on, open, real) ?? null);
12109
+ }
12044
12110
  }
12045
12111
  entry.hold?.(path, on, open, void 0, req.handle);
12046
12112
  return done;
@@ -12873,6 +12939,8 @@ var spinning = (globalThis.navigator?.hardwareConcurrency ?? 0) >= SPIN_CORES;
12873
12939
  var EARLY_WHOLE_FILE = 64 * 1024;
12874
12940
 
12875
12941
  // src/process/process-fds.ts
12942
+ var REFUSED = /* @__PURE__ */ new Set([wasiErrno("EACCES"), wasiErrno("EPERM")]);
12943
+ var OWN_ERRORS = 128 | 131072;
12876
12944
  var field3 = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
12877
12945
  var pinnedRoot;
12878
12946
  var rootKind = () => globalThis.navigator?.storage ? "opfs" : "memory";
@@ -17619,6 +17687,7 @@ var VfsNode = class {
17619
17687
  path;
17620
17688
  orphaned;
17621
17689
  id;
17690
+ ino;
17622
17691
  onDirty;
17623
17692
  onDirtyState;
17624
17693
  counted = false;
@@ -17971,8 +18040,12 @@ var VfsNodes = class {
17971
18040
  if (id2 !== void 0) this.know(node, id2);
17972
18041
  return node;
17973
18042
  }
17974
- open(path, pin, writable2 = false, id2) {
17975
- const node = this.named(path, id2) ?? this.create(path, id2, new VfsNode(this.fs, path, void 0, false, false, pin));
18043
+ open(path, pin, writable2 = false, id2, ino) {
18044
+ const found = this.named(path, id2);
18045
+ const same = !found || ino === void 0 || found.ino === void 0 || found.ino === ino;
18046
+ if (found && !same) this.orphan(found);
18047
+ const node = (same ? found : void 0) ?? this.create(path, id2, new VfsNode(this.fs, path, void 0, false, false, pin));
18048
+ node.ino ??= ino;
17976
18049
  node.opens++;
17977
18050
  if (writable2) node.writers++;
17978
18051
  return node;
@@ -18266,7 +18339,7 @@ function vfsFile(fs, opts, nodes) {
18266
18339
  const access2 = opts.flags & O_ACCMODE;
18267
18340
  const readable2 = access2 !== O_WRONLY;
18268
18341
  const writable2 = access2 === O_WRONLY || access2 === O_RDWR;
18269
- const node = !nodes || opts.orphan ? new VfsNode(fs, opts.path, opts.contents, opts.orphan === true, opts.dirty === true) : opts.contents !== void 0 ? nodes.adopt(opts.path, opts.contents, opts.dirty === true, writable2, opts.id) : nodes.open(opts.path, opts.pin, writable2, opts.id);
18342
+ const node = !nodes || opts.orphan ? new VfsNode(fs, opts.path, opts.contents, opts.orphan === true, opts.dirty === true) : opts.contents !== void 0 ? nodes.adopt(opts.path, opts.contents, opts.dirty === true, writable2, opts.id) : nodes.open(opts.path, opts.pin, writable2, opts.id, opts.ino);
18270
18343
  let openError;
18271
18344
  const atOpen = (op) => {
18272
18345
  void node.serial(op).catch((err) => {
@@ -19036,6 +19109,7 @@ var WasmProcess = class {
19036
19109
  const fd = this.fds.install(heldFile(), 3);
19037
19110
  try {
19038
19111
  const nodes = this.nodes;
19112
+ const gen = this.replacements?.generation() ?? 0;
19039
19113
  const path = await this.openPath(req, marked);
19040
19114
  if (inProc(path)) {
19041
19115
  this.fds.installAt(fd, await this.procFile(req, path));
@@ -19060,7 +19134,15 @@ var WasmProcess = class {
19060
19134
  }
19061
19135
  });
19062
19136
  } else {
19063
- this.fds.installAt(fd, this.openVfsFile(open, await nodes.identify(path), fs));
19137
+ await this.unmissed(
19138
+ () => this.openPath(req, marked),
19139
+ async (at) => {
19140
+ await this.stillOpen(at, req.handle);
19141
+ return nodes.identify(at);
19142
+ },
19143
+ (id2, at) => this.fds.installAt(fd, this.openVfsFile({ ...open, path: at }, id2, fs)),
19144
+ { at: path, gen }
19145
+ );
19064
19146
  }
19065
19147
  if (req.existing && !await present2(fs, path, true)) {
19066
19148
  throw new KernelError("ENOENT");
@@ -19241,7 +19323,8 @@ var WasmProcess = class {
19241
19323
  ...req.truncate ? { truncate: true } : {},
19242
19324
  ...req.create ? { create: true } : {},
19243
19325
  ...req.pin ? { pin: req.pin } : {},
19244
- ...id2 !== void 0 && !req.orphan ? { id: id2 } : {}
19326
+ ...id2 !== void 0 && !req.orphan ? { id: id2 } : {},
19327
+ ...req.ino !== void 0 && !req.orphan ? { ino: req.ino } : {}
19245
19328
  },
19246
19329
  this.nodes
19247
19330
  );
@@ -19412,9 +19495,27 @@ var WasmProcess = class {
19412
19495
  return false;
19413
19496
  }
19414
19497
  keptHandle;
19498
+ holdsHandle;
19499
+ replacements;
19500
+ async unmissed(path, look, make, first) {
19501
+ let given = first;
19502
+ for (; ; ) {
19503
+ const r = this.replacements;
19504
+ const gen = given?.gen ?? r?.generation() ?? 0;
19505
+ const at = given?.at ?? await path();
19506
+ given = void 0;
19507
+ await r?.settled(at);
19508
+ const found = await look(at);
19509
+ if (!r || !r.missed(at) && !r.changedSince(at, gen)) return make(found, at);
19510
+ }
19511
+ }
19512
+ async stillOpen(at, handle) {
19513
+ if (handle === void 0 || this.keptHandle?.(handle) !== void 0) return;
19514
+ if (this.holdsHandle?.(handle) !== false) return;
19515
+ if (!await present2(this.options.fs, at, true)) throw new KernelError("ENOENT");
19516
+ }
19415
19517
  async keptOr(path, handle) {
19416
- const held = handle === void 0 ? void 0 : this.keptHandle?.(handle);
19417
- if (held !== void 0) return held;
19518
+ if (handle !== void 0) return this.keptHandle?.(handle) ?? path;
19418
19519
  const kept = this.keptPath?.(path);
19419
19520
  return kept !== void 0 && !await present2(this.options.fs, path, true) ? kept : path;
19420
19521
  }
@@ -19424,25 +19525,37 @@ var WasmProcess = class {
19424
19525
  await this.fds.dup2Clipboard(req.share, req.fd);
19425
19526
  return;
19426
19527
  }
19427
- if (req.path === void 0) throw new KernelError("EINVAL");
19428
- const path = req.orphan ? req.path : await this.keptOr(await this.nodes.targetKey(req.path), req.handle);
19429
- const id2 = req.orphan ? void 0 : await this.nodes.identify(path);
19430
- if (!this.fds.get(req.fd).file.held) throw new KernelError("EBADF");
19431
- const file = vfsFile(
19432
- this.options.fs,
19433
- {
19434
- path,
19435
- flags: req.flags ?? 0,
19436
- position: req.position ?? 0,
19437
- ...req.contents !== void 0 ? { contents: req.contents } : {},
19438
- ...req.orphan ? { orphan: true } : {},
19439
- ...req.dirty ? { dirty: true } : {},
19440
- ...req.pin ? { pin: req.pin } : {},
19441
- ...id2 !== void 0 ? { id: id2 } : {}
19528
+ const asked = req.path;
19529
+ if (asked === void 0) throw new KernelError("EINVAL");
19530
+ const install = ([path, id2]) => {
19531
+ if (!this.fds.get(req.fd).file.held) throw new KernelError("EBADF");
19532
+ const file = vfsFile(
19533
+ this.options.fs,
19534
+ {
19535
+ path,
19536
+ flags: req.flags ?? 0,
19537
+ position: req.position ?? 0,
19538
+ ...req.contents !== void 0 ? { contents: req.contents } : {},
19539
+ ...req.orphan ? { orphan: true } : {},
19540
+ ...req.dirty ? { dirty: true } : {},
19541
+ ...req.pin ? { pin: req.pin } : {},
19542
+ ...id2 !== void 0 ? { id: id2 } : {},
19543
+ ...req.ino !== void 0 && path === asked ? { ino: req.ino } : {}
19544
+ },
19545
+ this.nodes
19546
+ );
19547
+ this.fds.installAt(req.fd, file);
19548
+ };
19549
+ if (req.orphan) return install([asked, void 0]);
19550
+ await this.unmissed(
19551
+ () => this.nodes.targetKey(asked),
19552
+ async (target) => {
19553
+ const at = await this.keptOr(target, req.handle);
19554
+ await this.stillOpen(at, req.handle);
19555
+ return [at, await this.nodes.identify(at)];
19442
19556
  },
19443
- this.nodes
19557
+ install
19444
19558
  );
19445
- this.fds.installAt(req.fd, file);
19446
19559
  }
19447
19560
  reserve(fd, min = 3, meta) {
19448
19561
  if (fd === void 0) return this.fds.install(heldFile(meta), Math.max(3, min));
@@ -20095,6 +20208,12 @@ function inherited(opts) {
20095
20208
  ...opts.cred ? { cred: opts.cred } : {}
20096
20209
  };
20097
20210
  }
20211
+ function heldBy(process2, holds2, replacements) {
20212
+ process2.keptPath = (path) => holds2.keptAt(path)?.hidden;
20213
+ process2.keptHandle = (handle) => holds2.keptFor(handle)?.hidden;
20214
+ process2.holdsHandle = (handle) => holds2.holdsHandle(handle);
20215
+ if (replacements) process2.replacements = replacements;
20216
+ }
20098
20217
  function holdingToken(opts, holds2, caller) {
20099
20218
  return mintSyncFsToken({
20100
20219
  ...opts.owners ? caller : { umask: caller.umask },
@@ -20102,6 +20221,7 @@ function holdingToken(opts, holds2, caller) {
20102
20221
  ...opts.links !== void 0 ? { links: opts.links } : {},
20103
20222
  ...opts.fresh ? { fresh: (path) => opts.fresh?.(path, caller.umask()) } : {},
20104
20223
  ...opts.source ? { source: opts.source } : {},
20224
+ ...opts.replacements ? { replacements: opts.replacements } : {},
20105
20225
  fs: opts.fs,
20106
20226
  noLinks: opts.noLinks,
20107
20227
  cwd: opts.cwd,
@@ -20240,8 +20360,7 @@ function spawnWasmProcess(opts) {
20240
20360
  created: created3,
20241
20361
  holdsKept: async (path) => path.includes(`/${UNLINKED_DIR}/`) && (holds2.keeps(path) || await process2.holds(path))
20242
20362
  });
20243
- process2.keptPath = (path) => holds2.keptAt(path)?.hidden;
20244
- process2.keptHandle = (handle2) => holds2.keptFor(handle2)?.hidden;
20363
+ heldBy(process2, holds2, opts.replacements);
20245
20364
  const worker = opts.createWorker();
20246
20365
  const dying = new Dying();
20247
20366
  const dispatch2 = (req, block) => dying.serve(
@@ -25429,6 +25548,7 @@ var Launcher = class {
25429
25548
  nodes: stack.nodes,
25430
25549
  held: this.held,
25431
25550
  unlinkGate: stack.unlinked.gate,
25551
+ replacements: stack.unlinked,
25432
25552
  statfs: (path) => this.mounts.statfs(path),
25433
25553
  mounts: () => this.mounts.list(),
25434
25554
  mount: (call, signal) => this.processMount(pid, call, signal),