@ai-ecoverse/slicc-kernel 1.108.0 → 1.108.2

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
@@ -322,7 +322,7 @@ A WASI command can name an ES module of its package that provides imports of its
322
322
 
323
323
  - `memory()`, `instance()` (after instantiation), `tid` (1 for the main thread), `argv`, `env`, `cwd()`;
324
324
  - `fs`: the synchronous filesystem the WASI calls use (absolute paths);
325
- - `fds`: `open(path, { read, write, append, create, exclusive, truncate, directory, nofollow, mode })` returns a WASI descriptor of the program; `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);
325
+ - `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);
326
326
  - `syscall(req)`: a kernel syscall, synchronously;
327
327
  - `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;
328
328
  - `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`;
@@ -922,7 +922,7 @@ The Biome, TypeScript, lefthook, Renovate and CI configuration comes from [slicc
922
922
 
923
923
  `tools/big-file.mjs [bytes]` is a manual check, not part of any suite. It writes a file of that size (64 MiB by default) through a tmpfs mount with the unit-test launcher, reads it back, and prints the peak RSS and its ratio to the file size. A 256 MiB file peaks at about 1.8 times its size. Before ranged I/O (#127), a 1.1 GiB file peaked at 18 GB of RSS. **Do not run it past 1 GiB on a workstation.** It refuses anything over 256 MiB unless `SLICC_BIG_FILE_I_HAVE_THE_RAM=1` is set. Measure a small file and extrapolate instead. The unit suite checks a 32 MiB file the same way, and allows a fixed 192 MiB for garbage V8 has yet to collect, which dominates at that size.
924
924
 
925
- Releases are cut by semantic-release on every push to `main`, in two jobs, and only on `main`. The first job runs on the bench pool, so it starts within a minute of the push, before `main` has moved on. It computes the version, tags the commit and creates the GitHub release, with `npmPublish: false`. A run that starts after `main` has moved skips; the run for the newer commit releases it. The second job runs on a GitHub-hosted runner, because npm's trusted publishing and provenance accept no self-hosted runner. It publishes the tagged commit with `tools/release-recover.mjs`. However long it waits for a runner, it publishes exactly the commit the run started on, so the provenance, the tag and the package's `gitHead` agree. For any version tagged at HEAD, `tools/release-recover.mjs` pushes the tag if origin lacks it, publishes the version if npm lacks it (with retries), and creates its GitHub release if that is missing too. So a failure after the version is tagged (a rejected push, a failed `npm publish`) doesn't strand it, and re-running the Release workflow completes it the same way.
925
+ Releases are cut by semantic-release on every push to `main`, in two jobs, and only on `main`. The first job runs on the bench pool, so it starts within a minute of the push, before `main` has moved on. It computes the version, tags the commit and creates the GitHub release, with `npmPublish: false`. A run that starts after `main` has moved skips; the run for the newer commit releases it. The second job runs on a GitHub-hosted runner, because npm's trusted publishing and provenance accept no self-hosted runner. It publishes the tagged commit with `tools/release-recover.mjs`. However long it waits for a runner, it publishes exactly the commit the run started on, so the provenance, the tag and the package's `gitHead` agree. For any version tagged at HEAD, `tools/release-recover.mjs` pushes the tag if origin lacks it, publishes the version if npm lacks it (with retries) and it is newer than npm's `latest` (an older one stays unpublished, so `latest` never moves back to it, and an `npm view` error fails the job instead of guessing; #837), and creates its GitHub release if that is missing too. So a failure after the version is tagged (a rejected push, a failed `npm publish`) doesn't strand it, and re-running the Release workflow completes it the same way.
926
926
 
927
927
  ### Certification (`cert-review`)
928
928
 
@@ -1084,9 +1084,9 @@ A threaded WASIX C program for `test/integration/thread-signal.test.mjs` (#520).
1084
1084
 
1085
1085
  A WASIX C program for `test/integration/long-timers.test.mjs` (#767).
1086
1086
  - `longwait alarm` sets `alarm(3000000)` (about 35 days), sleeps 0.5 s, and prints how many alarms came and how many seconds were left.
1087
- - `longwait select|ppoll|nanosleep` waits 3,000,000 s on a pipe that never gets data, until a 300 ms interval timer interrupts the wait.
1087
+ - `longwait select|ppoll|nanosleep` waits 3,000,000 s on a pipe that never gets data, until a 300 ms interval timer interrupts the wait, and prints `not before it` when the wait lasted at least 300 ms (`early` otherwise). It sets no upper bound, so a loaded CI host can't fail the row; a wait that never ends times the test out.
1088
1088
 
1089
- **Build:** `WASIX_SYSROOT_28=/path/to/wasix-sysroot ./build.sh`, with `wasixcc` 0.4.7 and binaryen's `wasm-opt` on `PATH`. `bin/longwait.wasm` is 44,010 bytes, sha256 `70ae2adfb46864fad3af0241fe26f401a62a5176ccd25ab82fe6588178cfb5c8`.
1089
+ **Build:** `WASIX_SYSROOT_28=/path/to/wasix-sysroot ./build.sh`, with `wasixcc` 0.4.7 and binaryen's `wasm-opt` on `PATH`. `bin/longwait.wasm` is 44,004 bytes, sha256 `e69d03f01479693666078297e781f5373719700c8534d1f2933749f5b3cee903`.
1090
1090
 
1091
1091
  ### `epollmask`
1092
1092
 
@@ -7985,7 +7985,7 @@ function satisfies(version, range2) {
7985
7985
  }
7986
7986
 
7987
7987
  // src/version.ts
7988
- var KERNEL_VERSION = true ? "1.108.0" : "0.0.0-dev";
7988
+ var KERNEL_VERSION = true ? "1.108.2" : "0.0.0-dev";
7989
7989
  var OS_RELEASE = "6.0.0-slicc";
7990
7990
  function procVersion() {
7991
7991
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -2497,7 +2497,7 @@ var init_wasi_fds = __esm({
2497
2497
  const flags = want === 6 ? O_RDWR : want === 2 ? O_WRONLY : 0;
2498
2498
  return openDevice2.call(this.kernel.sys, flags);
2499
2499
  }
2500
- open(path, oflags, rights, fdflags) {
2500
+ open(path, oflags, rights, fdflags, mode) {
2501
2501
  const device2 = deviceOf(path);
2502
2502
  if (device2) return this.install({ type: "device", device: device2 });
2503
2503
  const kernelDevice = this.openKernelDevice(path, oflags, fdflags, rights);
@@ -2518,13 +2518,16 @@ var init_wasi_fds = __esm({
2518
2518
  }
2519
2519
  if (!s && !(oflags & OFLAGS.CREAT)) throw new WasiError("ENOENT");
2520
2520
  refuseWrite(s, oflags, rights);
2521
- return this.regular(path, s, oflags, rights, fdflags);
2521
+ return this.regular(path, s, oflags, rights, fdflags, mode);
2522
2522
  }
2523
- regular(path, s, oflags, rights, fdflags) {
2523
+ regular(path, s, oflags, rights, fdflags, mode) {
2524
2524
  if (this.shared || this.kernelHolds(path, s)) {
2525
- return this.kernelFile(path, s, oflags, rights, fdflags);
2525
+ return this.kernelFile(path, s, oflags, rights, fdflags, mode);
2526
2526
  }
2527
- return this.install({ type: "file", file: this.file(path, s, oflags, rights, fdflags) });
2527
+ return this.install({
2528
+ type: "file",
2529
+ file: this.file(path, s, oflags, rights, fdflags, mode)
2530
+ });
2528
2531
  }
2529
2532
  kernelHolds(path, st) {
2530
2533
  for (const [fd, e] of this.table) {
@@ -2546,7 +2549,7 @@ var init_wasi_fds = __esm({
2546
2549
  } catch {
2547
2550
  }
2548
2551
  }
2549
- file(path, existing, oflags, rights, fdflags) {
2552
+ file(path, existing, oflags, rights, fdflags, mode) {
2550
2553
  const { readable: readable3, writable: writable2 } = openAccess(existing, oflags, rights);
2551
2554
  let buffer = this.buffers.get(path);
2552
2555
  if (buffer?.handle !== void 0 && this.fs.kept?.(buffer.handle)) {
@@ -2559,13 +2562,13 @@ var init_wasi_fds = __esm({
2559
2562
  if (this.fs.owners) this.fs.access?.(path, want, "open");
2560
2563
  if (oflags & OFLAGS.TRUNC) buffer.truncate(0);
2561
2564
  } else {
2562
- buffer = this.freshBuffer(path, existing, oflags, want);
2565
+ buffer = this.freshBuffer(path, existing, oflags, want, mode);
2563
2566
  }
2564
2567
  buffer.opens++;
2565
2568
  return new LocalFile(buffer, readable3, writable2, (fdflags & FDFLAGS.APPEND) !== 0);
2566
2569
  }
2567
- freshBuffer(path, existing, oflags, want) {
2568
- const made = !existing && this.createNew(path, oflags);
2570
+ freshBuffer(path, existing, oflags, want, mode) {
2571
+ const made = !existing && this.createNew(path, oflags, mode);
2569
2572
  const empty = made || (oflags & OFLAGS.TRUNC) !== 0;
2570
2573
  if (existing?.ranged) this.fs.invalidate?.();
2571
2574
  const seen = this.fs.changes?.now();
@@ -2595,11 +2598,11 @@ var init_wasi_fds = __esm({
2595
2598
  if (id !== void 0) this.know(buffer, id);
2596
2599
  return buffer;
2597
2600
  }
2598
- kernelFile(path, existing, oflags, rights, fdflags) {
2601
+ kernelFile(path, existing, oflags, rights, fdflags, mode) {
2599
2602
  const { readable: readable3, writable: writable2 } = openAccess(existing, oflags, rights);
2600
2603
  const append = (fdflags & FDFLAGS.APPEND) !== 0;
2601
2604
  const flags = (writable2 ? readable3 ? O_RDWR : O_WRONLY : 0) | (append ? O_APPEND : 0);
2602
- const made = !existing && this.createNew(path, oflags);
2605
+ const made = !existing && this.createNew(path, oflags, mode);
2603
2606
  const truncate = made || (oflags & OFLAGS.TRUNC) !== 0;
2604
2607
  const fd = this.kernel.sys.openVfs(path, flags, 0, {
2605
2608
  ...truncate ? { truncate } : {},
@@ -2612,13 +2615,13 @@ var init_wasi_fds = __esm({
2612
2615
  this.bump();
2613
2616
  return fd;
2614
2617
  }
2615
- createNew(path, oflags) {
2618
+ createNew(path, oflags, mode) {
2616
2619
  if (!this.fs.create) {
2617
2620
  this.fs.writeFile(path, new Uint8Array(0));
2618
2621
  return true;
2619
2622
  }
2620
2623
  try {
2621
- this.fs.create(path, void 0, true);
2624
+ this.fs.create(path, mode, true);
2622
2625
  return true;
2623
2626
  } catch (err) {
2624
2627
  if (oflags & OFLAGS.EXCL || err.code !== "EEXIST") throw err;
@@ -4897,13 +4900,15 @@ function importsContext({
4897
4900
  const fds = {
4898
4901
  open(path, o = {}) {
4899
4902
  const abs = host.fds.resolve(3, path);
4900
- if (o.nofollow && fs.exists(abs) && fs.lstat(abs).isSymbolicLink)
4903
+ const fresh = o.create === true && o.exclusive === true && owners && fs.create !== void 0;
4904
+ if (!fresh && o.nofollow && fs.exists(abs) && fs.lstat(abs).isSymbolicLink)
4901
4905
  throw new WasiError("ELOOP");
4902
- const existed = fs.exists(abs);
4906
+ const existed = !fresh && fs.exists(abs);
4903
4907
  const oflags = (o.create ? OFLAGS.CREAT : 0) | (o.exclusive ? OFLAGS.EXCL : 0) | (o.truncate ? OFLAGS.TRUNC : 0) | (o.directory ? OFLAGS.DIRECTORY : 0);
4904
4908
  const rights = (o.write ? RIGHTS.FD_WRITE : 0n) | (o.read || !o.write ? RIGHTS.FD_READ : 0n);
4905
- const fd = host.fds.open(abs, oflags, rights, o.append ? FDFLAGS.APPEND : 0);
4906
- if (o.mode !== void 0 && !existed) fs.chmod(abs, o.mode);
4909
+ const flags = o.append ? FDFLAGS.APPEND : 0;
4910
+ const fd = host.fds.open(abs, oflags, rights, flags, fresh ? o.mode : void 0);
4911
+ if (o.mode !== void 0 && !existed && !fresh) fs.chmod(abs, o.mode);
4907
4912
  return fd;
4908
4913
  },
4909
4914
  close(fd) {
@@ -5167,7 +5172,7 @@ var KERNEL_VERSION, OS_RELEASE;
5167
5172
  var init_version = __esm({
5168
5173
  "src/version.ts"() {
5169
5174
  "use strict";
5170
- KERNEL_VERSION = true ? "1.108.0" : "0.0.0-dev";
5175
+ KERNEL_VERSION = true ? "1.108.2" : "0.0.0-dev";
5171
5176
  OS_RELEASE = "6.0.0-slicc";
5172
5177
  }
5173
5178
  });