@ai-ecoverse/slicc-kernel 1.110.3 → 1.110.5

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/README.md CHANGED
@@ -324,7 +324,7 @@ A WASI command can name an ES module of its package that provides imports of its
324
324
 
325
325
  - `memory()`, `instance()` (after instantiation), `tid` (1 for the main thread), `argv`, `env`, `cwd()`;
326
326
  - `fs`: the synchronous filesystem the WASI calls use (absolute paths);
327
- - `fds`: `open(path, { read, write, append, create, exclusive, truncate, directory, nofollow, mode })` returns a WASI descriptor of the program; `mode` is a new file's mode. With `create` and `exclusive` under users `report` or `enforce`, the file is created with it, less the umask, as `open(2)` does, and the name is only checked by the create itself (a symlink there is `EEXIST`). Otherwise the mode is set exactly once the file is open; `close`, `fstat` (`{ kind, path, mode, uid, gid, size, ino, mtimeMs }`), `fchmod`, and `tryLock(fd, exclusive)` / `unlock(fd)`: advisory locks held by the kernel across processes and threads, keyed by path, released on unlock, on closing the descriptor and at exit (`tryLock` returns 0, or 6 when another process holds the lock);
327
+ - `fds`: `open(path, { read, write, append, create, exclusive, truncate, directory, nofollow, mode })` returns a WASI descriptor of the program; `mode` is a new file's mode. With `create` and `exclusive` under users `report` or `enforce`, the file is created with it, less the umask, as `open(2)` does, and the name is only checked by the create itself (a symlink there is `EEXIST`). Otherwise the mode is set exactly once the file is open; `close`, `fstat` (`{ kind, path, mode, uid, gid, size, ino, mtimeMs }`; an open file's size is the descriptor's own, so writes not yet flushed count, while the other fields come from a stat of its path, as WASI's `fd_filestat_get` gives them), `fchmod`, and `tryLock(fd, exclusive)` / `unlock(fd)`: advisory locks held by the kernel across processes and threads, keyed by path, released on unlock, on closing the descriptor and at exit (`tryLock` returns 0, or 6 when another process holds the lock);
328
328
  - `syscall(req)`: a kernel syscall, synchronously;
329
329
  - `net.connect({ host, port, nonblock })` connects a TCP socket to the kernel's loopback and returns its kernel descriptor. `host` is `localhost` or `127.x.y.z`; anything else, or a port outside 1–65535, is `EINVAL`. A refused connection throws `ECONNREFUSED`. The connection carries the program's own identity, as any connect from its process does, so a [page facade](#page-facades) such as `SLICC_LINK_URL` sees the program's stamp. With `nonblock` it returns at once, and `net.ready(fd)` answers 0 once a connect is complete, `EINPROGRESS` (26) while it isn't, or the connect's WASI errno (`SO_ERROR`). On the loopback a connect completes at once, so `ready` is 0 straight away. `ready` is meant for a descriptor from `net.connect`. The descriptor is read and written with `fd-read` and `fd-write` and closed with `fd-close`, as below, and `fd-select` (`{ op: 'fd-select', read: [fds], write: [fds], timeoutMs }`, answering `{ read, write }` with the ready ones; `timeoutMs: -1` waits without a limit) waits until it's readable or writable;
330
330
  - `spawn({ argv, env, cwd, stdin, stdout, stderr })` starts a command (resolved like `kernel.run`) as a child and returns `{ pid, stdin, stdout, stderr }`. `env` is the child's whole environment (the program's own by default), `cwd` the program's by default. Each stdio is `'inherit'` (the default: the program's own), `'null'`, or `'pipe'`: a kernel pipe whose end the result holds as a descriptor, read and written with `fd-read` (`{ op: 'fd-read', fd, max }`, an empty read at the end), `fd-write` (`{ op: 'fd-write', fd, body }`) and `fd-close`, through `syscall` or `async.submit`; the child's ends are closed in the program. A command that does not exist throws `ENOENT`;
@@ -6176,7 +6176,7 @@ function satisfies(version, range2) {
6176
6176
  }
6177
6177
 
6178
6178
  // src/version.ts
6179
- var KERNEL_VERSION = true ? "1.110.3" : "0.0.0-dev";
6179
+ var KERNEL_VERSION = true ? "1.110.5" : "0.0.0-dev";
6180
6180
  var OS_RELEASE = "6.0.0-slicc";
6181
6181
  function procVersion() {
6182
6182
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -4918,6 +4918,14 @@ function importsContext({
4918
4918
  }
4919
4919
  return void 0;
4920
4920
  };
4921
+ const sizedOf = (fd) => {
4922
+ const e = host.fds.get(fd);
4923
+ if (e.type === "file") return { path: e.file.path, size: e.file.size() };
4924
+ if (e.type === "kernel" && host.fds.kind(fd, e) === "file") {
4925
+ return call2({ op: "fd-vfs-stat", fd });
4926
+ }
4927
+ return { path: pathOf(fd) };
4928
+ };
4921
4929
  const requirePath = (fd) => {
4922
4930
  const path = pathOf(fd);
4923
4931
  if (path === void 0) throw new WasiError("EBADF");
@@ -4948,19 +4956,19 @@ function importsContext({
4948
4956
  },
4949
4957
  fstat(fd) {
4950
4958
  const e = host.fds.get(fd);
4951
- const path = pathOf(fd);
4959
+ const { path, size } = sizedOf(fd);
4952
4960
  if (path === void 0) {
4953
4961
  const kind = e.type === "device" ? "device" : "stream";
4954
4962
  return { kind, mode: kind === "device" ? 8630 : 4480, ...live(), size: 0 };
4955
4963
  }
4956
- host.fds.flushPath(path);
4964
+ if (size === void 0) host.fds.flushPath(path);
4957
4965
  const s = fs.stat(path);
4958
4966
  return {
4959
4967
  kind: s.isDirectory ? "dir" : "file",
4960
4968
  path,
4961
4969
  mode: s.mode ?? (s.isDirectory ? 16877 : 33188),
4962
4970
  ...s.uid !== void 0 && s.gid !== void 0 ? { uid: s.uid, gid: s.gid } : live(),
4963
- size: s.size,
4971
+ size: size ?? s.size,
4964
4972
  ...s.ino !== void 0 ? { ino: s.ino } : {},
4965
4973
  ...s.mtimeMs !== void 0 ? { mtimeMs: s.mtimeMs } : {}
4966
4974
  };
@@ -5204,7 +5212,7 @@ var KERNEL_VERSION, OS_RELEASE;
5204
5212
  var init_version = __esm({
5205
5213
  "src/version.ts"() {
5206
5214
  "use strict";
5207
- KERNEL_VERSION = true ? "1.110.3" : "0.0.0-dev";
5215
+ KERNEL_VERSION = true ? "1.110.5" : "0.0.0-dev";
5208
5216
  OS_RELEASE = "6.0.0-slicc";
5209
5217
  }
5210
5218
  });
@@ -6476,12 +6484,13 @@ function fetchOp(kernel) {
6476
6484
  throw signal.aborted ? signal.reason : failed(err);
6477
6485
  }
6478
6486
  };
6479
- const body = (handle, signal) => {
6487
+ const body = (handle, request) => {
6488
+ const { signal } = request;
6480
6489
  let aborted;
6481
6490
  const settle = () => {
6482
6491
  if (aborted) signal.removeEventListener("abort", aborted);
6483
6492
  };
6484
- return new ReadableStream(
6493
+ const stream = new ReadableStream(
6485
6494
  {
6486
6495
  start(controller) {
6487
6496
  aborted = () => {
@@ -6516,8 +6525,10 @@ function fetchOp(kernel) {
6516
6525
  },
6517
6526
  { highWaterMark: 0 }
6518
6527
  );
6528
+ keptRequests.set(stream, request);
6529
+ return stream;
6519
6530
  };
6520
- const respond = (head, method, redirected, encoded, signal) => {
6531
+ const respond = (head, method, redirected, encoded, request) => {
6521
6532
  if (head.status < 200 || head.status > 599) {
6522
6533
  void close(head.handle);
6523
6534
  throw failed(new JsCallError("EPROTO", `status ${head.status}`));
@@ -6525,7 +6536,7 @@ function fetchOp(kernel) {
6525
6536
  const empty = method === "HEAD" || NULL_BODY.has(head.status);
6526
6537
  if (empty) void close(head.handle);
6527
6538
  const headers = new Headers(head.headers);
6528
- let stream = empty ? null : body(head.handle, signal);
6539
+ let stream = empty ? null : body(head.handle, request);
6529
6540
  const coding = headers.get("content-encoding")?.trim().toLowerCase();
6530
6541
  if (stream && encoded && coding && DECODED.has(coding)) {
6531
6542
  const format = coding === "deflate" ? "deflate" : "gzip";
@@ -6533,6 +6544,7 @@ function fetchOp(kernel) {
6533
6544
  new DecompressionStream(format)
6534
6545
  );
6535
6546
  headers.delete("content-length");
6547
+ keptRequests.set(stream, request);
6536
6548
  }
6537
6549
  const response = new Response(stream, {
6538
6550
  status: head.status,
@@ -6578,7 +6590,7 @@ function fetchOp(kernel) {
6578
6590
  const follow2 = known.manualRedirects && REDIRECTS.has(head.status) && location !== void 0 && request.redirect !== "manual";
6579
6591
  if (!follow2) {
6580
6592
  const redirected = hops > 0 || head.redirected === true;
6581
- return respond(head, hop.method, redirected, known.encodedBodies, signal);
6593
+ return respond(head, hop.method, redirected, known.encodedBodies, request);
6582
6594
  }
6583
6595
  await close(head.handle);
6584
6596
  if (request.redirect === "error") throw failed(new Error("unexpected redirect"));
@@ -6587,7 +6599,7 @@ function fetchOp(kernel) {
6587
6599
  }
6588
6600
  };
6589
6601
  }
6590
- var CHUNK2, MAX_REDIRECTS, NULL_BODY, REDIRECTS, BODY_HEADERS, DECODED, CREDENTIALS, BAD_PORTS, OVER, TOKEN, QUOTABLE, SPACE, BASE64, SLICE;
6602
+ var CHUNK2, MAX_REDIRECTS, keptRequests, NULL_BODY, REDIRECTS, BODY_HEADERS, DECODED, CREDENTIALS, BAD_PORTS, OVER, TOKEN, QUOTABLE, SPACE, BASE64, SLICE;
6591
6603
  var init_js_fetch = __esm({
6592
6604
  "src/process/js/js-fetch.ts"() {
6593
6605
  "use strict";
@@ -6595,6 +6607,7 @@ var init_js_fetch = __esm({
6595
6607
  init_js_kernel();
6596
6608
  CHUNK2 = 64 * 1024;
6597
6609
  MAX_REDIRECTS = 20;
6610
+ keptRequests = /* @__PURE__ */ new WeakMap();
6598
6611
  NULL_BODY = /* @__PURE__ */ new Set([101, 103, 204, 205, 304]);
6599
6612
  REDIRECTS = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
6600
6613
  BODY_HEADERS = /* @__PURE__ */ new Set([