@ai-ecoverse/slicc-kernel 1.134.4 → 1.135.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 +2 -1
- package/dist/kernel-worker.js +46 -11
- package/dist/kernel-worker.js.map +2 -2
- package/dist/node-process-worker.js +5 -4
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +46 -11
- package/dist/node.js.map +2 -2
- package/dist/process-worker.js +5 -4
- package/dist/process-worker.js.map +2 -2
- package/dist/types/kernel/host.d.ts +2 -0
- package/dist/types/kernel/js-threads.d.ts +10 -0
- package/dist/types/process/wasi/wasi-procfs.d.ts +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1099,6 +1099,7 @@ The kernel writes `/etc/passwd` and `/etc/group` when it starts (see [Users](#us
|
|
|
1099
1099
|
In a browser every process worker of the page shares one renderer. V8 reserves about 8 GiB of address space for each 32-bit wasm memory, whatever its declared maximum, and its sandbox holds about 1 TiB. So a page runs about 125 wasm processes (or programs that own a wasm memory) at once, counting everything in the renderer (#970). Node has no such ceiling, and neither does Linux. The kernel keeps processes inside that ceiling:
|
|
1100
1100
|
- **The ceiling:** 112 by default in a browser and none in Node (`createNodeKernel({ wasmMemories: { ceiling, idleMs } })` sets one in Node; `idleMs`, the quiet spell before `EAGAIN` below, 10 s by default, is there for tests). It's the kernel's count of live wasm processes, with the kernel's other wasm memories in the page left outside it. When an instantiation runs out of memory anyway, the kernel learns the real ceiling at that moment (the live count minus one), and that learned value wins over the default. A learned ceiling is never below 16, since an OOM at a low count means something outside it (another tab in the same renderer) filled the renderer. It's raised by 8 for each minute without another OOM, back to the default.
|
|
1101
1101
|
- **Admission:** a spawn, fork, exec or `kernel.run` at the ceiling waits for another process to exit. It keeps waiting as long as processes exit, are admitted or finish starting (a process becoming ready counts, so a slow host that is still booting the processes ahead of it doesn't fail the spawn, #1196), and fails with `EAGAIN` only after 10 s with none of these. A long `make -j` or `xargs -P` therefore queues, and a pipeline that needs more live processes than the ceiling fails cleanly. bash's own retry on a fork's `EAGAIN` (`fork: retry: Resource temporarily unavailable`) handles the rest.
|
|
1102
|
+
- **JS workers count too** (#1133): each JS process and each `thread.spawn` thread takes one slot, whether or not it creates wasm memories, so a worker that creates several under-counts within a small factor, and a shared memory posted to threads is one reservation however many threads use it. A JS worker also costs the renderer about 65 MB of RAM, which the same bound keeps in check. `thread.spawn` waits for a slot as a spawn does, and rejects with `EAGAIN` after the same quiet spell. With many JS workers live, wasm processes wait earlier, which is deliberate. Node has no ceiling, so nothing changes there, and the per-process thread cap (`SLICC_JS_THREADS`) still applies on top.
|
|
1102
1103
|
- **Close to the ceiling** (within 16 of it), the kernel waits for each new process to finish instantiating before the spawn returns. If it ran out of memory, the kernel starts it again, quietly, once there's room, so the caller sees no failure.
|
|
1103
1104
|
- **The rare residual case:** a process that fails to instantiate with nobody waiting on it, which happens only when something outside the count fills the renderer. It ends with status 126 and `<program>: cannot allocate memory for a new process (too many processes at once)` on its stderr, never a JS `RangeError`.
|
|
1104
1105
|
- **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.
|
|
@@ -1247,7 +1248,7 @@ The tools in `tools/cert-review/`:
|
|
|
1247
1248
|
- and record, which re-hashes the candidate's artifact against the pack job's sha256.
|
|
1248
1249
|
- **The verdict** goes into the commit status on the pull request's head and a comment on the pull request. Certified is green. A FAIL is red with the line, and the pull request needs a fix. **INCOMPLETE** (a job that didn't succeed, no verdict, a suite without results) is red with `re-run the failed jobs`, never a silent pass. Main moving on after a review doesn't trigger another one; a push does.
|
|
1249
1250
|
- **Merge groups only look up.** On `merge_group`, the job lists the group's pull requests (its merge commits) and requires, for each one, a green status on the head being merged, or no behaviour change. Otherwise it's red, naming the pull request. Then it adds the group's downstream verdict. The group's `ci / test` covers the combined tree.
|
|
1250
|
-
- **Downstream, once per merge group:** the `merge group pack` job packs the group's tree with `main`'s tools (`x.y.z-group.<run>`), and `downstream bios canary` calls slicc-bios's `canary.yml` at a pinned full sha (`
|
|
1251
|
+
- **Downstream, once per merge group:** the `merge group pack` job packs the group's tree with `main`'s tools (`x.y.z-group.<run>`), and `downstream bios canary` calls slicc-bios's `canary.yml` at a pinned full sha (`1f071319…`, never a tag) with that tarball, bound by artifact id, digest and sha256, on the `sweep`, `guard-prompt`, `guard-lagging`, `k4-upgrade`, `k4-agent-modes` and `link-serve` shards, each run once, on the runner the `canary runner` job picks: `.github/runner.mjs`'s `decide()` from `main`, as `ci.yml` uses it, gives `vars.CERT_CANARY_RUNNER` only to a merge group whose entries are all same-repo PRs, and `ubuntu-latest` otherwise, without the variable, or if the decider fails (bios honours a runner only for merge groups and pushes to main in ai-ecoverse, so rolling back is unsetting the variable). The verdict line names the shards, or their count past 32 characters (`6 shards`), so a status description (140 characters) keeps the reason. `downstream.mjs` judges its result (`downstreamOf` in `lib.mjs`), and the lookup requires it. The `merge group` job reads that result as `result.json` from the canary's own artifact, downloaded by the call's `artifact-id` with `digest-mismatch: error`, not from the `result` output: that output can be up to 512 KB, and one environment variable holds 128 KB, so passing it that way stopped the step from starting at all (`Argument list too long`, runs 39166647175 and 39168823799). A missing or unreadable artifact leaves no result, so the group is INCOMPLETE:
|
|
1251
1252
|
- **PASS:** the candidate passes, `downstream: PASS bios … N pass`;
|
|
1252
1253
|
- **FAIL:** a regression, or a failing test (by the counts, even without its rows) is **not certified**, and the group is red;
|
|
1253
1254
|
- **INCOMPLETE** blocks too: no result, a result from another bios than the pinned one, a missing shard, a shard that exited without a failing test, a refused candidate, 0 tests run, or no test passed;
|
package/dist/kernel-worker.js
CHANGED
|
@@ -7098,7 +7098,7 @@ function satisfies(version, range2) {
|
|
|
7098
7098
|
}
|
|
7099
7099
|
|
|
7100
7100
|
// src/version.ts
|
|
7101
|
-
var KERNEL_VERSION = true ? "1.
|
|
7101
|
+
var KERNEL_VERSION = true ? "1.135.0" : "0.0.0-dev";
|
|
7102
7102
|
var OS_RELEASE = "6.0.0-slicc";
|
|
7103
7103
|
function procVersion() {
|
|
7104
7104
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -23100,23 +23100,55 @@ var JsThreads = class {
|
|
|
23100
23100
|
get size() {
|
|
23101
23101
|
return this.live.size;
|
|
23102
23102
|
}
|
|
23103
|
+
pending = 0;
|
|
23104
|
+
get admission() {
|
|
23105
|
+
return this.deps.admission;
|
|
23106
|
+
}
|
|
23103
23107
|
spawn(msg) {
|
|
23104
|
-
|
|
23105
|
-
|
|
23106
|
-
|
|
23107
|
-
control,
|
|
23108
|
+
if (this.closed || this.live.size + this.pending >= this.deps.cap) {
|
|
23109
|
+
this.refuse(
|
|
23110
|
+
msg,
|
|
23108
23111
|
this.closed ? { errno: "ESRCH", message: "the process is ending" } : { errno: "EAGAIN", message: `more than ${this.deps.cap} threads` }
|
|
23109
23112
|
);
|
|
23110
|
-
control.close();
|
|
23111
|
-
port.close();
|
|
23112
23113
|
return;
|
|
23113
23114
|
}
|
|
23115
|
+
this.pending++;
|
|
23116
|
+
this.admission.admit().then(
|
|
23117
|
+
() => {
|
|
23118
|
+
this.pending--;
|
|
23119
|
+
if (!this.closed) {
|
|
23120
|
+
let worker;
|
|
23121
|
+
try {
|
|
23122
|
+
worker = this.deps.createWorker();
|
|
23123
|
+
} catch {
|
|
23124
|
+
this.admission.ended();
|
|
23125
|
+
this.refuse(msg, { errno: "EAGAIN", message: "no worker for the thread" });
|
|
23126
|
+
return;
|
|
23127
|
+
}
|
|
23128
|
+
this.begin(msg, worker);
|
|
23129
|
+
return;
|
|
23130
|
+
}
|
|
23131
|
+
this.admission.ended();
|
|
23132
|
+
this.refuse(msg, { errno: "ESRCH", message: "the process is ending" });
|
|
23133
|
+
},
|
|
23134
|
+
() => {
|
|
23135
|
+
this.pending--;
|
|
23136
|
+
this.refuse(msg, { errno: "EAGAIN", message: "no room for another worker" });
|
|
23137
|
+
}
|
|
23138
|
+
);
|
|
23139
|
+
}
|
|
23140
|
+
refuse(msg, why) {
|
|
23141
|
+
answer(msg.control, why);
|
|
23142
|
+
msg.control.close();
|
|
23143
|
+
msg.port.close();
|
|
23144
|
+
}
|
|
23145
|
+
begin(msg, worker) {
|
|
23146
|
+
const { control, port } = msg;
|
|
23114
23147
|
const tid = ++this.last;
|
|
23115
23148
|
const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
23116
23149
|
const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
|
|
23117
23150
|
const owned4 = new SharedArrayBuffer(4 * (1 + JS_THREAD_OWNED_FDS));
|
|
23118
23151
|
if (this.frozen) Atomics.store(header3, SAB_I_STOP, 1);
|
|
23119
|
-
const worker = this.deps.createWorker();
|
|
23120
23152
|
const clock = this.deps.clocks.thread(tid + 1, sab);
|
|
23121
23153
|
let ended = false;
|
|
23122
23154
|
const end = (code) => {
|
|
@@ -23135,6 +23167,7 @@ var JsThreads = class {
|
|
|
23135
23167
|
responder.dispose();
|
|
23136
23168
|
lane.dispose();
|
|
23137
23169
|
this.deps.clocks.threadEnded(tid + 1);
|
|
23170
|
+
this.admission.ended();
|
|
23138
23171
|
worker.terminate();
|
|
23139
23172
|
for (const fd of ownedFds(owned4)) {
|
|
23140
23173
|
void this.deps.dispatch({ op: "fd-close", fd });
|
|
@@ -23186,6 +23219,7 @@ var JsThreads = class {
|
|
|
23186
23219
|
end(JS_THREAD_CRASHED);
|
|
23187
23220
|
return;
|
|
23188
23221
|
}
|
|
23222
|
+
this.admission.started();
|
|
23189
23223
|
answer(control, { tid });
|
|
23190
23224
|
}
|
|
23191
23225
|
crashed(message3, end) {
|
|
@@ -23680,7 +23714,8 @@ function jsThreadsOf(opts, process, token, dispatch2, clocks, header3) {
|
|
|
23680
23714
|
openLane: (laneDispatch) => openLane(token, laneDispatch),
|
|
23681
23715
|
attach: (worker, sab, threadDispatch) => attachSyncSabResponder(worker, sab, token, { dispatch: threadDispatch }),
|
|
23682
23716
|
dispatch: dispatch2,
|
|
23683
|
-
clocks
|
|
23717
|
+
clocks,
|
|
23718
|
+
admission: opts.admission
|
|
23684
23719
|
});
|
|
23685
23720
|
process.onState((state) => threads.stopped(state === "stopped"));
|
|
23686
23721
|
return threads;
|
|
@@ -28082,7 +28117,6 @@ var Launcher = class {
|
|
|
28082
28117
|
if (req.links !== void 0) this.links.set(pid, req.links);
|
|
28083
28118
|
}
|
|
28084
28119
|
async admitted(wasm, fds, start2) {
|
|
28085
|
-
if (!wasm) return start2(fds);
|
|
28086
28120
|
for (; ; ) {
|
|
28087
28121
|
await this.memories.admit().catch(async (err) => {
|
|
28088
28122
|
await fds.closeAll();
|
|
@@ -28093,7 +28127,7 @@ var Launcher = class {
|
|
|
28093
28127
|
void Promise.resolve(handle2.ready).then(() => this.memories.started());
|
|
28094
28128
|
return handle2;
|
|
28095
28129
|
};
|
|
28096
|
-
if (!this.memories.near()) {
|
|
28130
|
+
if (!wasm || !this.memories.near()) {
|
|
28097
28131
|
try {
|
|
28098
28132
|
return counted2(start2(fds));
|
|
28099
28133
|
} catch (err) {
|
|
@@ -28171,6 +28205,7 @@ var Launcher = class {
|
|
|
28171
28205
|
noLinks: stack.noLinks,
|
|
28172
28206
|
...this.prefixes.length > 0 && !stack.writer ? { readonlyAt: (path) => isProtected(this.prefixes, path) } : {},
|
|
28173
28207
|
createWorker: this.createWorker,
|
|
28208
|
+
admission: this.memories,
|
|
28174
28209
|
onError: req.report,
|
|
28175
28210
|
onOom: () => {
|
|
28176
28211
|
this.memories.learn();
|