Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
38e00db
Browser: stop retaining stale immediate cancellations
brandonpayton Jul 13, 2026
321aa7b
test(browser): preserve guest stderr on nonzero exit
brandonpayton Jul 13, 2026
297b547
test(browser): cover guest HTTP through the configured CORS proxy
brandonpayton Jul 13, 2026
902e1f8
test(fork-instrument): verify reproducible output across processes
brandonpayton Jul 13, 2026
b26b750
MariaDB: share writable-directory setup across VFS images
brandonpayton Jul 13, 2026
8d9e1df
VFS: share canonical rootfs overlay assembly
brandonpayton Jul 13, 2026
1d8085e
Test SjLj across C++ noexcept boundaries
brandonpayton Jul 13, 2026
19cb17d
VFS: keep positioned I/O off shared file offsets
brandonpayton Jul 13, 2026
1092a47
host: preserve output buffers on zero-byte syscalls
brandonpayton Jul 13, 2026
a757932
Runner: start examples with requested user and group IDs
brandonpayton Jul 13, 2026
4d9c74f
mremap: reject growth without matching mapping metadata
brandonpayton Jul 13, 2026
06551eb
Locks: report shared lock-table exhaustion as ENOLCK
brandonpayton Jul 13, 2026
5fc2387
VFS: synchronize directory file descriptors
brandonpayton Jul 13, 2026
75d9d3c
libc: zero stat fields the kernel does not report
brandonpayton Jul 13, 2026
b82a32d
SQLite: keep recursive tests within WebAssembly stack limits
brandonpayton Jul 14, 2026
0ba71dd
SQLite tests: run all-mode child jobs on Kandelo
brandonpayton Jul 13, 2026
c7eb124
SQLite tests: preserve truthful outcome evidence
brandonpayton Jul 13, 2026
590f48d
SQLite tests: account for UTF-16 STAT4 sample bytes
brandonpayton Jul 13, 2026
224faa7
SQLite: clean up TestRecover Tcl commands
brandonpayton Jul 13, 2026
3e3070b
libc: align wasm32 pthread entry stacks
brandonpayton Jul 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions apps/browser-demos/lib/init/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,3 @@ export { COREUTILS_NAMES } from "./shell-binaries";

// Service worker bridge
export { initServiceWorkerBridge } from "./service-worker-bridge";

// MariaDB directory setup
export { populateMariadbDirs } from "./mariadb-config";
24 changes: 0 additions & 24 deletions apps/browser-demos/lib/init/mariadb-config.ts

This file was deleted.

113 changes: 3 additions & 110 deletions apps/browser-demos/lib/kernel-owned-boot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@
// left is the small, transient per-boot image-build FS; these helpers track it
// and nudge WebKit's collector to reclaim it between boots.
import { MemoryFileSystem } from "@host/vfs/memory-fs";
import { overlayEtcFromRootfs } from "@host/vfs/rootfs-overlay";
// @ts-expect-error — vite ?url virtual module (resolved by the kernel-artifacts plugin)
import rootfsVfsUrl from "@rootfs-vfs?url";

export { overlayEtcFromRootfs };

const WEBKIT_RECLAIM_TIMEOUT_MS = 1_500;
const WEBKIT_RECLAIM_STEP_MS = 150;
const WEBKIT_RECLAIM_PRESSURE_BYTES = 32 * 1024 * 1024;
Expand Down Expand Up @@ -91,116 +94,6 @@ export function createEmptyBuildFs(maxByteLength = 64 * 1024 * 1024): MemoryFile
return MemoryFileSystem.create(sab, maxByteLength);
}

const S_IFMT = 0xf000;
const S_IFREG = 0x8000;
const S_IFDIR = 0x4000;
const S_IFLNK = 0xa000;

function copyMissingRootfsPath(
source: MemoryFileSystem,
target: MemoryFileSystem,
path: string,
): void {
const sourceStat = source.lstat(path);
const sourceKind = sourceStat.mode & S_IFMT;
let targetKind: number | null = null;
try {
targetKind = target.lstat(path).mode & S_IFMT;
} catch {
// Missing in the caller's image: copy it from the canonical rootfs.
}

// Existing caller-owned leaves always win. Existing directories merge with
// canonical directories so a demo can override one file without losing the
// rest of that subtree.
if (targetKind !== null && (sourceKind !== S_IFDIR || targetKind !== S_IFDIR)) {
return;
}

if (sourceKind === S_IFDIR) {
if (targetKind === null) {
target.mkdirWithOwner(
path,
sourceStat.mode & 0o7777,
sourceStat.uid,
sourceStat.gid,
);
}
const dh = source.opendir(path);
try {
for (;;) {
const entry = source.readdir(dh);
if (entry === null) break;
if (entry.name === "." || entry.name === "..") continue;
copyMissingRootfsPath(
source,
target,
path === "/" ? `/${entry.name}` : `${path}/${entry.name}`,
);
}
} finally {
source.closedir(dh);
}
return;
}

if (sourceKind === S_IFLNK) {
target.symlinkWithOwner(
source.readlink(path),
path,
sourceStat.uid,
sourceStat.gid,
);
return;
}

if (sourceKind !== S_IFREG) {
throw new Error(`Unsupported canonical /etc file type at ${path}`);
}

const bytes = new Uint8Array(sourceStat.size);
const fd = source.open(path, 0, 0);
let offset = 0;
try {
while (offset < bytes.length) {
const count = source.read(
fd,
bytes.subarray(offset),
null,
bytes.length - offset,
);
if (count <= 0) {
throw new Error(
`Short read while copying canonical rootfs path ${path}: ` +
`${offset}/${bytes.length} bytes`,
);
}
offset += count;
}
} finally {
source.close(fd);
}
target.createFileWithOwner(
path,
sourceStat.mode & 0o7777,
sourceStat.uid,
sourceStat.gid,
bytes,
);
}

/**
* Recursively merge canonical `/etc` state into `target`, without overwriting
* files or symlinks the caller already wrote. This replaces the legacy
* worker-side `/etc` overlay that `kernel.init()` performed: demos that start
* from a small custom image still inherit rootfs-owned account, resolver, TLS,
* and other configuration through the normal VFS path.
*/
export function overlayEtcFromRootfs(target: MemoryFileSystem, rootfsImage: Uint8Array): void {
const source = MemoryFileSystem.fromImage(rootfsImage);
copyMissingRootfsPath(source, target, "/etc");
}

/**
* Convenience: an empty build FS pre-seeded with `/etc` from the canonical
* rootfs — the kernel-owned equivalent of the legacy empty-FS + init()-overlay
Expand Down
39 changes: 2 additions & 37 deletions apps/browser-demos/pages/network/network-demo-worker.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { CAPTURED_STDIO, CentralizedKernelWorker } from "@host/kernel-worker";
import { installBrowserSetImmediatePolyfill } from "@host/browser-immediate-polyfill";
import { BrowserWorkerAdapter } from "@host/worker-adapter-browser";
import { detectPtrWidth, extractHeapBase } from "@host/constants";
import { LocalVirtualNetwork } from "@host/networking/virtual-network";
Expand All @@ -16,43 +17,7 @@ import workerEntryUrl from "@host/worker-entry-browser.ts?worker&url";
import ncWasmUrl from "@binaries/programs/wasm32/nc.wasm?url";
import curlWasmUrl from "@binaries/programs/wasm32/curl.wasm?url";

if (typeof (globalThis as typeof globalThis & { setImmediate?: unknown }).setImmediate === "undefined") {
const queue: Array<{ id: number; fn: (...args: unknown[]) => void; args: unknown[] }> = [];
const cancelled = new Set<number>();
const channel = new MessageChannel();
let nextId = 0;
let scheduled = false;
let flushing = false;

channel.port1.onmessage = () => {
scheduled = false;
flushing = true;
const count = queue.length;
for (let i = 0; i < count && queue.length > 0; i++) {
const entry = queue.shift()!;
if (cancelled.delete(entry.id)) continue;
entry.fn(...entry.args);
}
flushing = false;
if (queue.length > 0 && !scheduled) {
scheduled = true;
channel.port2.postMessage(null);
}
};

(globalThis as typeof globalThis & { setImmediate: (fn: (...args: unknown[]) => void, ...args: unknown[]) => number }).setImmediate =
(fn, ...args) => {
const id = ++nextId;
queue.push({ id, fn, args });
if (!scheduled && !flushing) {
scheduled = true;
channel.port2.postMessage(null);
}
return id;
};
(globalThis as typeof globalThis & { clearImmediate: (id: number) => void }).clearImmediate =
(id) => { cancelled.add(id); };
}
installBrowserSetImmediatePolyfill();

const MAX_PAGES = 16384;
const CH_TOTAL_SIZE = 72 + 65536;
Expand Down
26 changes: 19 additions & 7 deletions apps/browser-demos/pages/sqlite-test/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import { BrowserKernel } from "@host/browser-kernel-host";
import { MemoryFileSystem } from "@host/vfs/memory-fs";
import { writeVfsFile } from "@host/vfs/image-helpers";
import { finalizeKernelOwnedImage, settleWebKitReclaim } from "../../lib/kernel-owned-boot";
import {
patchTestrunnerForKandelo,
testrunnerPlatformShim,
} from "./testrunner-patch";
import kernelWasmUrl from "@kernel-wasm?url";

declare global {
Expand Down Expand Up @@ -91,6 +95,20 @@ async function collectArtifactsFromKernel(
return artifacts.length > 0 ? artifacts : undefined;
}

function installTestrunnerPatches(fs: MemoryFileSystem): void {
const runnerPath = "/sqlite/test/testrunner.tcl";
const decoder = new TextDecoder();
const runner = decoder.decode(readVfsFile(fs, runnerPath));
writeVfsFile(fs, runnerPath, patchTestrunnerForKandelo(runner), 0o644);

writeVfsFile(fs, "/sqlite/kandelo-testrunner.tcl", [
testrunnerPlatformShim,
"set argv0 test/testrunner.tcl",
"source $argv0",
"",
].join("\n"), 0o644);
}

function createFs(): MemoryFileSystem {
if (!vfsImageBytes) throw new Error("SQLite test VFS image not loaded");
const fs = MemoryFileSystem.fromImage(vfsImageBytes, {
Expand Down Expand Up @@ -153,13 +171,7 @@ async function init() {
// SharedArrayBuffer across the per-test loop (Safari OOM fix).
const buildFs = createFs();
if (argv[1] === "kandelo-testrunner.tcl") {
writeVfsFile(buildFs, "/sqlite/kandelo-testrunner.tcl", [
"set ::tcl_platform(os) OpenBSD",
"set ::tcl_platform(platform) unix",
"set argv0 test/testrunner.tcl",
"source $argv0",
"",
].join("\n"), 0o644);
installTestrunnerPatches(buildFs);
}
const vfsImage = await finalizeKernelOwnedImage(buildFs);
const kernel = new BrowserKernel({
Expand Down
Loading
Loading