mirror of
https://github.com/HeyPuter/gex.git
synced 2026-11-13 20:12:43 -10:00
web/ is a Vite app with xterm.js and three demos: run a binary you supply, a BusyBox userspace with a shell in it, and Debian with apt (not finished -- it needs the network layer). Getting the first two working meant four things the browser host did not have. `gexc seed` writes a module that translates nothing: the entry stub, the miss stub, an empty dispatch table. Every branch it takes misses, so the runtime translator behind it produces the whole program -- which makes one 1.4 KB module enough to run *any* guest. A page cannot run the ahead-of-time compiler, so without this a page can only run programs somebody compiled for it in advance. It runs a static hello in 0.2s and busybox in 0.3s. Interactive input. A read on an empty stream is now a BlockOp rather than a short read, decided before the call by asking the handle whether a read would wait -- which is different from turning an EAGAIN into a wait afterwards, because a descriptor opened O_NONBLOCK is supposed to see the EAGAIN. The browser scheduler parks the thread, and when every thread is waiting it gives the wasm stack back to JS, which is the only place a page can wait for a keystroke at all. Termios is real. TCSETS used to return success and discard what it set, so a shell that turned off ICANON and ECHO believed it had taken over line editing while the page was still doing its own, and every keystroke landed twice. The kernel keeps the struct and the page follows it. fork and exec in the browser, which the outcome match used to answer with "unsupported". fork is done by checkpoint: the parent's memory, kernel, threads and dispatch state are copied aside, the child runs in place, and the parent is restored when it exits with the child's pid already in x0. The parent cannot run while the child does; for fork-then-wait, which is every shell, that is invisible. That last one took a real bug to get right. Pipelines crashed with a jump to an unaligned stack address. Restoring the parent restored its dispatch page table too -- including the slot allocation mark -- so the next translation handed out slots the child had already filled, and a page whose directory entry survived the restore dispatched into another page's code. Slots are now monotonic across a checkpoint: the parent keeps its pages, allocation carries on from wherever the child got to. `ls /bin | head -4`, `echo a b c | wc -w` and a for loop all work in an interactive shell in the browser runtime. 89 stages pass. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01KcidnrZ5aLqKoBJBqdjx9d
25 lines
510 B
JSON
25 lines
510 B
JSON
{
|
|
"name": "web",
|
|
"version": "1.0.0",
|
|
"description": "",
|
|
"main": "index.js",
|
|
"scripts": {
|
|
"dev": "vite",
|
|
"build": "vite build",
|
|
"preview": "vite preview",
|
|
"assets": "./build-assets.sh"
|
|
},
|
|
"keywords": [],
|
|
"author": "",
|
|
"license": "ISC",
|
|
"type": "module",
|
|
"devDependencies": {
|
|
"vite": "^8.2.0"
|
|
},
|
|
"dependencies": {
|
|
"@mercuryworkshop/wisp-js": "^0.4.1",
|
|
"@xterm/addon-fit": "^0.11.0",
|
|
"@xterm/addon-web-links": "^0.12.0",
|
|
"@xterm/xterm": "^6.0.0"
|
|
}
|
|
} |