@ai-ecoverse/slicc-kernel 1.127.0 → 1.128.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/README.md CHANGED
@@ -191,6 +191,8 @@ When the kernel goes away (the page closed or reloaded, `terminate()`), pending
191
191
 
192
192
  `@ai-ecoverse/slicc-kernel/node` runs the same kernel in Node without a browser, so packages built for SLICC can test against it. It is a testing entry, not a supported runtime: there is no OPFS, JS programs get the same guard as in the page but no sandbox (see [JS programs](#js-programs)), and nothing beyond what its tests use is promised.
193
193
 
194
+ **Known issue, Node 24** ([#1129](https://github.com/ai-ecoverse/slicc-kernel/issues/1129)): V8 in Node 24 sometimes crashes the whole Node process with a `jit_page` check failure while a process worker starts or is torn down. slicc-cli measured 15 crashes in 1,600 runs on Node 24 and none in 1,600 on Node 26. Use Node 26 where you can. The `Node versions` workflow (nightly, and on demand) runs the suites that start the Node kernel on both versions and counts the crashes in each job's summary, so the `engines` floor can follow the numbers.
195
+
194
196
  ```js
195
197
  import { createNodeKernel, nodeTransport } from '@ai-ecoverse/slicc-kernel/node';
196
198
 
@@ -333,6 +335,7 @@ A WASI command can name an ES module of its package that provides imports of its
333
335
 
334
336
  - `memory()`, `instance()` (after instantiation), `tid` (1 for the main thread), `argv`, `env`, `cwd()`;
335
337
  - `fs`: the synchronous filesystem the WASI calls use (absolute paths);
338
+ - `fs.copyFile(from, to, { mode, excl })` copies a regular file inside the kernel, as `slicc_fs.path_copy_file` does (below): `mode` (default `0666`) less the umask, `excl` for `O_EXCL`. It throws the kernel's fs errors (`code` `EEXIST`, `ENOENT`, `EXDEV`, …). An older kernel's `ctx.fs` has no `copyFile`, so a module checks `typeof ctx.fs.copyFile === 'function'`;
336
339
  - `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);
337
340
  - `syscall(req)`: a kernel syscall, synchronously;
338
341
  - `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;
@@ -830,6 +833,7 @@ WASI and WASIX have no call for file modes, so the kernel adds the import module
830
833
  | `path_filestat_owner(dirfd, lookupflags, path, path_len, filestat_out, out)` | `path_filestat_get` (with its preview1 lookup flags: `1` follows a symlink) and the owner of the same path, in one call, so a libc's `stat` costs one call either way |
831
834
  | `path_mkfifo(dirfd, path, path_len, mode)` | `mkfifo`/`mkfifoat` and `mknod(S_IFIFO)` (homescoop#878): makes a [FIFO](#filesystem) with `mode & ~umask`, relative to `dirfd` (`AT_FDCWD` is `-2`). It doesn't follow a link in the last component, so an existing name, also a FIFO, a dangling link, a directory or the root, is `EEXIST`, and an empty name is `ENOENT` (#972). A mount without FIFOs answers `EPERM` |
832
835
  | `path_access(dirfd, path, path_len, amode, flags)` | `faccessat`: `amode` is `R_OK` 4, `W_OK` 2, `X_OK` 1 or `F_OK` 0; the check uses the real uid and gid, or the effective ones with `flags & 2` (`AT_EACCESS`), and the link itself with `flags & 1`. With `users: 'off'` it checks only that the path exists, as a libc without it does (see [Permissions](#permissions)) |
836
+ | `path_copy_file(src_dirfd, src, src_len, dst_dirfd, dst, dst_len, mode, flags)` | copies a regular file inside the kernel, with no bytes through the program ([#1017](https://github.com/ai-ecoverse/slicc-kernel/issues/1017)). Paths resolve as in `path_open`; an absolute one ignores its dirfd, and `AT_FDCWD` is `-2`. The source is followed through symlinks; the destination's last component never is. The new file gets `mode & ~umask` and the caller as owner, with the permissions of a create: read on the source, write and search on the destination's directory. `flags & 1` (`COPY_EXCL`) makes it `O_EXCL`, so of two copies racing to one name exactly one succeeds and the other gets `EEXIST`. Without it, an existing file is replaced in place, as with `O_TRUNC`. `flags & 2` (`COPY_MODE`) takes the source's permission bits instead of `mode`; other bits are `EINVAL`. A failure after the create removes the new name. Other processes of the kernel that look at the destination wait until the copy has committed, so they see the old file or none, then the whole copy. Another tab sharing the OPFS root can see it empty until the commit, as with any create followed by a write. A source that isn't a regular file is `EINVAL`, and a copy between two mounts is `EXDEV`, so a program falls back to reading and writing. On the OPFS root a copy is one kernel call and about 5 OPFS lookups |
833
837
 
834
838
  The kernel's device nodes answer the mode and owner an Emscripten program sees for them ([#1028](https://github.com/ai-ecoverse/slicc-kernel/issues/1028)):
835
839
  - `/dev/null`, `/dev/zero`, `/dev/full`, `/dev/random`, `/dev/urandom` and `/dev/tty` are root's character devices with `0666`. `/dev/tty` also stats when the process has no controlling terminal; opening it then is `ENXIO`, as on Linux.
@@ -1034,7 +1038,7 @@ In a browser every process worker of the page shares one renderer. V8 reserves a
1034
1038
  - **Below a learned ceiling,** a process that still runs out of memory is started again once another process exits, and the spawn fails with `EAGAIN` after 10 s with none.
1035
1039
  - **`/proc/sys/kernel/slicc_wasm_memories`** reads `<live> <ceiling> <source>`. The source is `default`, `learned`, or `none` (with the ceiling 0).
1036
1040
 
1037
- `/proc/sys/kernel/slicc_shared_root` reads `1` while another kernel shares the root (a tab, or a second kernel in the page) and `0` otherwise. A peer whose kernel ends (its tab closes or reloads) stops counting at once: each kernel queues a request for every peer's alive Web Lock, and the grant tells it the peer has gone ([#984](https://github.com/ai-ecoverse/slicc-kernel/issues/984)). `/proc/sys/kernel/slicc_fs_calls` reads the number of path calls (lookups, stats, opens, creates, removals and the like) the kernel has served its programs since it started. `/proc/sys/kernel/slicc_opfs_calls` counts the OPFS calls the kernel has made to look names up and read stats (`getFile`, `getFileHandle`, `getDirectoryHandle`, `resolve`). With an idle peer, a tar unpack makes at most 1.5 times the calls it makes alone ([#984](https://github.com/ai-ecoverse/slicc-kernel/issues/984)).
1041
+ `/proc/sys/kernel/slicc_shared_root` reads `1` while another kernel shares the root (a tab, or a second kernel in the page) and `0` otherwise. A peer whose kernel ends (its tab closes or reloads) stops counting at once: each kernel queues a request for every peer's alive Web Lock, and the grant tells it the peer has gone ([#984](https://github.com/ai-ecoverse/slicc-kernel/issues/984)). `/proc/sys/kernel/slicc_fs_calls` reads the number of path calls (lookups, stats, opens, creates, removals and the like) the kernel has served its programs since it started. `/proc/sys/kernel/slicc_opfs_calls` counts the OPFS calls the kernel has made to look names up and read stats (`getFile`, `getFileHandle`, `getDirectoryHandle`, `resolve`). `/proc/sys/kernel/slicc_opfs_ops` counts every request the root file system makes of OPFS: those lookups, plus creates, writes (one per write, truncate or write session), reads, listings, renames and removals ([#1017](https://github.com/ai-ecoverse/slicc-kernel/issues/1017)). With an idle peer, a tar unpack makes at most 1.5 times the calls it makes alone ([#984](https://github.com/ai-ecoverse/slicc-kernel/issues/984)).
1038
1042
 
1039
1043
  ### Metadata
1040
1044