@ai-ecoverse/slicc-kernel 1.116.1 → 1.117.0

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
@@ -931,7 +931,8 @@ function openPipe(capacity) {
931
931
  },
932
932
  close: () => pipe.closeRead(),
933
933
  poll: () => ({ readable: pipe.readReady, writable: false, hangup: pipe.writersGone }),
934
- changed: (signal) => pipe.changed(signal)
934
+ changed: (signal) => pipe.changed(signal),
935
+ identity: pipe
935
936
  }),
936
937
  write: new OpenFile({
937
938
  write: async (bytes, signal) => {
@@ -943,7 +944,8 @@ function openPipe(capacity) {
943
944
  },
944
945
  close: () => pipe.closeWrite(),
945
946
  poll: () => ({ readable: false, writable: pipe.writeReady, hangup: pipe.readersGone }),
946
- changed: (signal) => pipe.changed(signal)
947
+ changed: (signal) => pipe.changed(signal),
948
+ identity: pipe
947
949
  })
948
950
  };
949
951
  }
@@ -4817,13 +4819,20 @@ var OpfsFs = class {
4817
4819
  if (handle.kind === "directory") throw fsError("EISDIR", path);
4818
4820
  return handle;
4819
4821
  }
4822
+ async refuseNode(path, empty) {
4823
+ if (!empty) return;
4824
+ const [entry] = await this.meta.get([(await this.locate(path, true)).path]);
4825
+ if (entry?.fifo || entry?.socket) throw fsError("ENXIO", path);
4826
+ }
4820
4827
  async readFileBuffer(path) {
4821
4828
  const handle = await this.existing(path);
4822
- return this.retrying(
4829
+ const bytes = await this.retrying(
4823
4830
  path,
4824
4831
  async () => new Uint8Array(await (await handle.getFile()).arrayBuffer()),
4825
4832
  false
4826
4833
  );
4834
+ await this.refuseNode(path, bytes.length === 0);
4835
+ return bytes;
4827
4836
  }
4828
4837
  async readVersioned(path, cached = false) {
4829
4838
  const handle = await this.existing(path);
@@ -4833,6 +4842,7 @@ var OpfsFs = class {
4833
4842
  const stamp = await this.stamp(path, cached);
4834
4843
  const file = await handle.getFile();
4835
4844
  const bytes = new Uint8Array(await file.arrayBuffer());
4845
+ await this.refuseNode(path, bytes.length === 0);
4836
4846
  return { bytes, version: `${file.lastModified}:${file.size}:${stamp}` };
4837
4847
  },
4838
4848
  false
@@ -4854,7 +4864,11 @@ var OpfsFs = class {
4854
4864
  const handle = await this.existing(path);
4855
4865
  return this.retrying(
4856
4866
  path,
4857
- async () => new Uint8Array(await (await handle.getFile()).slice(offset, offset + length2).arrayBuffer()),
4867
+ async () => {
4868
+ const file = await handle.getFile();
4869
+ await this.refuseNode(path, file.size === 0);
4870
+ return new Uint8Array(await file.slice(offset, offset + length2).arrayBuffer());
4871
+ },
4858
4872
  false
4859
4873
  );
4860
4874
  }
@@ -4870,6 +4884,7 @@ var OpfsFs = class {
4870
4884
  }
4871
4885
  async truncate(path, size) {
4872
4886
  const handle = await this.existing(path, true);
4887
+ await this.refuseNode(path, (await handle.getFile()).size === 0);
4873
4888
  const resolve2 = this.ranged || this.remote?.watched();
4874
4889
  const target = resolve2 || this.counted.length > 0 ? (await this.locate(path, true)).path : path;
4875
4890
  await this.counting(target);
@@ -4922,6 +4937,10 @@ var OpfsFs = class {
4922
4937
  }
4923
4938
  async fileFor(path) {
4924
4939
  const [target, existed] = await this.writeTarget(path);
4940
+ if (existed) {
4941
+ const [entry] = await this.meta.get([target]);
4942
+ if (entry?.fifo || entry?.socket) throw fsError("ENXIO", path);
4943
+ }
4925
4944
  const [dir, name2] = await this.parent(target);
4926
4945
  try {
4927
4946
  const handle = await this.inDir(
@@ -6559,7 +6578,7 @@ function satisfies(version, range2) {
6559
6578
  }
6560
6579
 
6561
6580
  // src/version.ts
6562
- var KERNEL_VERSION = true ? "1.116.1" : "0.0.0-dev";
6581
+ var KERNEL_VERSION = true ? "1.117.0" : "0.0.0-dev";
6563
6582
  var OS_RELEASE = "6.0.0-slicc";
6564
6583
  function procVersion() {
6565
6584
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -9703,6 +9722,7 @@ var FifoTable = class {
9703
9722
  let open = true;
9704
9723
  return new OpenFile({
9705
9724
  fifo: path,
9725
+ identity: fifo,
9706
9726
  ...reads ? {
9707
9727
  read: async (max, signal) => {
9708
9728
  try {
@@ -13136,7 +13156,71 @@ function lockRange(start2, len) {
13136
13156
  if (from < 0) throw new KernelError("EINVAL");
13137
13157
  return { start: from, end };
13138
13158
  }
13159
+ function changedAt(wakers, key, signal) {
13160
+ return new Promise((resolve2, reject) => {
13161
+ const set3 = wakers.get(key) ?? /* @__PURE__ */ new Set();
13162
+ wakers.set(key, set3);
13163
+ const done4 = () => {
13164
+ set3.delete(wake);
13165
+ if (set3.size === 0 && wakers.get(key) === set3) wakers.delete(key);
13166
+ signal.removeEventListener("abort", abort);
13167
+ };
13168
+ const wake = () => {
13169
+ done4();
13170
+ resolve2();
13171
+ };
13172
+ const abort = () => {
13173
+ done4();
13174
+ reject(new KernelError("EINTR"));
13175
+ };
13176
+ set3.add(wake);
13177
+ signal.addEventListener("abort", abort, { once: true });
13178
+ });
13179
+ }
13180
+ function wakeAt(wakers, key) {
13181
+ for (const wake of [...wakers.get(key) ?? []]) wake();
13182
+ }
13183
+ var FlockTable = class {
13184
+ held = /* @__PURE__ */ new Map();
13185
+ keys = /* @__PURE__ */ new WeakMap();
13186
+ wakers = /* @__PURE__ */ new Map();
13187
+ free(key, owner, kind) {
13188
+ for (const [other, has] of this.held.get(key) ?? [])
13189
+ if (other !== owner && (kind === "exclusive" || has === "exclusive")) return false;
13190
+ return true;
13191
+ }
13192
+ set(key, owner, kind) {
13193
+ const has = this.held.get(key)?.get(owner);
13194
+ if (has === kind) return true;
13195
+ if (has !== void 0) this.drop(owner);
13196
+ if (kind === "unlock") return true;
13197
+ if (!this.free(key, owner, kind)) return false;
13198
+ const holders = this.held.get(key) ?? /* @__PURE__ */ new Map();
13199
+ holders.set(owner, kind);
13200
+ this.held.set(key, holders);
13201
+ this.keys.set(owner, key);
13202
+ return true;
13203
+ }
13204
+ async wait(key, owner, kind, blocking) {
13205
+ if (this.set(key, owner, kind)) return;
13206
+ const signal = blocking();
13207
+ while (!this.set(key, owner, kind)) {
13208
+ if (signal.aborted) throw new KernelError("EINTR");
13209
+ await changedAt(this.wakers, key, signal);
13210
+ }
13211
+ }
13212
+ drop(owner) {
13213
+ const key = this.keys.get(owner);
13214
+ if (key === void 0) return;
13215
+ this.keys.delete(owner);
13216
+ const holders = this.held.get(key);
13217
+ holders?.delete(owner);
13218
+ if (holders?.size === 0) this.held.delete(key);
13219
+ wakeAt(this.wakers, key);
13220
+ }
13221
+ };
13139
13222
  var LockTable = class {
13223
+ flocks = new FlockTable();
13140
13224
  records = /* @__PURE__ */ new Map();
13141
13225
  blocked = /* @__PURE__ */ new Map();
13142
13226
  wakers = /* @__PURE__ */ new Map();
@@ -13194,28 +13278,10 @@ var LockTable = class {
13194
13278
  return false;
13195
13279
  }
13196
13280
  changed(key, signal) {
13197
- return new Promise((resolve2, reject) => {
13198
- const set3 = this.wakers.get(key) ?? /* @__PURE__ */ new Set();
13199
- this.wakers.set(key, set3);
13200
- const done4 = () => {
13201
- set3.delete(wake);
13202
- if (set3.size === 0 && this.wakers.get(key) === set3) this.wakers.delete(key);
13203
- signal.removeEventListener("abort", abort);
13204
- };
13205
- const wake = () => {
13206
- done4();
13207
- resolve2();
13208
- };
13209
- const abort = () => {
13210
- done4();
13211
- reject(new KernelError("EINTR"));
13212
- };
13213
- set3.add(wake);
13214
- signal.addEventListener("abort", abort, { once: true });
13215
- });
13281
+ return changedAt(this.wakers, key, signal);
13216
13282
  }
13217
13283
  wake(key) {
13218
- for (const wake of [...this.wakers.get(key) ?? []]) wake();
13284
+ wakeAt(this.wakers, key);
13219
13285
  }
13220
13286
  store(key, locks) {
13221
13287
  if (locks.length === 0) this.records.delete(key);
@@ -13280,6 +13346,7 @@ var HOST_OPS = [
13280
13346
  "lk-set",
13281
13347
  "lk-get",
13282
13348
  "lk-close",
13349
+ "flock",
13283
13350
  "async-submit",
13284
13351
  "async-wait",
13285
13352
  "async-take",
@@ -13432,6 +13499,8 @@ async function hostSyscall(req, ctx) {
13432
13499
  case "lk-get":
13433
13500
  case "lk-close":
13434
13501
  return recordLock2(req, ctx);
13502
+ case "flock":
13503
+ return flock(req, ctx);
13435
13504
  case "async-submit":
13436
13505
  if (!ctx.valid(req.req)) throw new KernelError("EINVAL");
13437
13506
  if (req.ack) ctx.ops.ack(req.ack);
@@ -13454,6 +13523,17 @@ async function hostSyscall(req, ctx) {
13454
13523
  return done2;
13455
13524
  }
13456
13525
  }
13526
+ var FLOCK_KINDS = /* @__PURE__ */ new Set(["shared", "exclusive", "unlock"]);
13527
+ async function flock(req, ctx) {
13528
+ const { locks, flockOf } = ctx;
13529
+ if (!locks || !flockOf) throw new KernelError("ENOLCK");
13530
+ if (!FLOCK_KINDS.has(req.kind)) throw new KernelError("EINVAL");
13531
+ const { key, owner } = await flockOf(req.fd);
13532
+ if (req.kind !== "unlock" && req.wait)
13533
+ await locks.flocks.wait(key, owner, req.kind, ctx.blocking);
13534
+ else if (!locks.flocks.set(key, owner, req.kind)) throw new KernelError("EAGAIN");
13535
+ return done2;
13536
+ }
13457
13537
  async function recordLock2(req, ctx) {
13458
13538
  const { locks, fileKey } = ctx;
13459
13539
  if (!locks || !fileKey) throw new KernelError("ENOLCK");
@@ -17424,6 +17504,18 @@ var fileKeys = /* @__PURE__ */ new WeakMap();
17424
17504
  function identityKey(st, path) {
17425
17505
  return st.ino === void 0 ? path : `${st.dev ?? 0}:${st.ino}`;
17426
17506
  }
17507
+ var objectIds = /* @__PURE__ */ new WeakMap();
17508
+ var nextObjectId = 1;
17509
+ function objectKey(file) {
17510
+ const at = file.tty ?? file.identity ?? file.pty ?? file;
17511
+ let id2 = objectIds.get(at);
17512
+ if (id2 === void 0) {
17513
+ id2 = nextObjectId++;
17514
+ objectIds.set(at, id2);
17515
+ }
17516
+ return `object:${id2}`;
17517
+ }
17518
+ var flockHooked = /* @__PURE__ */ new WeakSet();
17427
17519
  var DYING = { ok: false, errno: "EINTR", message: "the process is being killed" };
17428
17520
  var HOSTS_ONLY = new Resolver({ routes: new Routes() });
17429
17521
  function timeLeft(req, started) {
@@ -17724,6 +17816,7 @@ var WasmProcess = class {
17724
17816
  pid: this.pid,
17725
17817
  owner: () => this.lockOwner(),
17726
17818
  fileKey: (target, kind, setting) => this.lockKey(target, kind, setting),
17819
+ flockOf: (fd) => this.flockOf(fd),
17727
17820
  locks: this.options.locks,
17728
17821
  ops: this.asyncOps,
17729
17822
  blocking: () => this.blockingSignal(cancelled),
@@ -17792,6 +17885,7 @@ var WasmProcess = class {
17792
17885
  throw new KernelError("EBADF");
17793
17886
  const known = file ? fileKeys.get(file) : this.pathKeys.get(target.path ?? "");
17794
17887
  if (kind === "close" && !file && target.path !== void 0) this.pathKeys.delete(target.path);
17888
+ if (access2 && !access2.stat) return objectKey(access2);
17795
17889
  const want = kind === "read" ? R_OK : kind === "write" ? W_OK : 0;
17796
17890
  const path = await this.lockPath(target, want);
17797
17891
  if (known !== void 0) return known;
@@ -17806,6 +17900,33 @@ var WasmProcess = class {
17806
17900
  else if (this.pathKeys.size < 4096) this.pathKeys.set(path, key);
17807
17901
  return key;
17808
17902
  }
17903
+ async flockOf(fd) {
17904
+ const open = this.fds.get(fd);
17905
+ const { locks } = this.options;
17906
+ if (locks && !flockHooked.has(open)) {
17907
+ flockHooked.add(open);
17908
+ open.onClose(() => locks.flocks.drop(open));
17909
+ }
17910
+ return { key: await this.objectKeyOf(open), owner: open };
17911
+ }
17912
+ async objectKeyOf(open) {
17913
+ const { file } = open;
17914
+ const meta = file.heldMeta;
17915
+ if (meta && "device" in meta) return `device:${meta.device}`;
17916
+ if (meta && "dir" in meta) {
17917
+ const st2 = await this.options.fs.stat?.(meta.dir).catch(() => void 0);
17918
+ return st2 ? identityKey(st2, meta.dir) : objectKey(file);
17919
+ }
17920
+ const known = fileKeys.get(open);
17921
+ if (known !== void 0) return known;
17922
+ const vfs = await file.stat?.().catch(() => void 0);
17923
+ if (!vfs || vfs.orphan) return objectKey(file);
17924
+ const st = await this.options.fs.stat?.(vfs.path).catch(() => void 0);
17925
+ if (!st) return objectKey(file);
17926
+ const key = identityKey(st, vfs.path);
17927
+ fileKeys.set(open, key);
17928
+ return key;
17929
+ }
17809
17930
  async dropRecordLocks(fd) {
17810
17931
  const { locks } = this.options;
17811
17932
  const owner = this.options.jobs?.shown(this.pid) ?? this.pid;
@@ -20086,6 +20207,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
20086
20207
  },
20087
20208
  changed,
20088
20209
  ...file.tty ? { tty: file.tty } : {},
20210
+ identity: file.identity ?? file,
20089
20211
  ...file.clipboard ? { clipboard: file.clipboard } : {},
20090
20212
  ...file.write ? {
20091
20213
  write: async (bytes, signal) => {