Commit Graph
648 Commits
Author SHA1 Message Date
bomberfishandClaude Opus 5.5 2917292e2b docs/d3d-webgpu.md: divisors and strides
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_f0a06c8a084b4b2ca4f7f291183d507d
2026-10-14 09:35:29 -04:00
bomberfishandClaude Opus 5.5 898b896cca docs/d3d-webgpu.md: d3d9 numbers
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_f0a06c8a084b4b2ca4f7f291183d507d
2026-10-14 08:46:26 -04:00
bomberfishandClaude Opus 5.5 6ced269ef4 docs/d3d-webgpu.md: point sprites, legacy fixups
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_f0a06c8a084b4b2ca4f7f291183d507d
2026-10-14 08:41:42 -04:00
bomberfishandClaude Opus 5.5 ac61f8be6c docs/d3d-webgpu.md: d3d9 visual to the end; triangle fans
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_f0a06c8a084b4b2ca4f7f291183d507d
2026-10-14 08:32:49 -04:00
bomberfishandClaude Opus 5.5 c09fcfa781 docs/d3d-webgpu.md: presentation through webgpu.h surfaces, the plan
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_f0a06c8a084b4b2ca4f7f291183d507d
2026-10-14 08:27:50 -04:00
bomberfishandClaude Opus 5.5 2a4c30d4e3 docs/d3d-webgpu.md: the compositor serves /dev/gex-gpu
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_f0a06c8a084b4b2ca4f7f291183d507d
2026-10-14 08:21:45 -04:00
bomberfishandClaude Opus 5.5 f62e174882 docs/d3d-webgpu.md: glass frames
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_f0a06c8a084b4b2ca4f7f291183d507d
2026-10-14 07:39:49 -04:00
bomberfishandClaude Opus 5.5 bd01f2e4c0 docs/d3d-webgpu.md: what the WebGPU renderer does by other means, and today's numbers
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_f0a06c8a084b4b2ca4f7f291183d507d
2026-10-14 07:09:52 -04:00
bomberfishandClaude Opus 5.5 c66356ff20 docs/d3d-webgpu.md: typed buffer views, and d3d10core run to the end
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_f0a06c8a084b4b2ca4f7f291183d507d
2026-10-14 06:57:17 -04:00
bomberfishandClaude Opus 5.5 ee972959cd docs/d3d-webgpu.md: test results after fog, out-of-range fetches and R11G11B10
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_f0a06c8a084b4b2ca4f7f291183d507d
2026-10-14 06:45:32 -04:00
bomberfishandClaude Opus 5.5 3e18f87daf docs/d3d-webgpu.md: the glass path as it stands
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_f0a06c8a084b4b2ca4f7f291183d507d
2026-10-14 06:10:18 -04:00
bomberfishandClaude Opus 5.5 dc024c6951 docs/d3d-webgpu.md: Aero by a glass compositor of our own, and why
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_f0a06c8a084b4b2ca4f7f291183d507d
2026-10-14 05:57:13 -04:00
bomberfishandClaude Opus 5.5 0ee25865b4 docs/d3d-webgpu.md: gpu-smoke in Chrome
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_f0a06c8a084b4b2ca4f7f291183d507d
2026-10-14 05:44:45 -04:00
bomberfishandClaude Opus 5.5 fec4c7a69b docs/d3d-webgpu.md: /dev/gex-gpu, natively and in the browser runtime
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_f0a06c8a084b4b2ca4f7f291183d507d
2026-10-14 05:43:59 -04:00
bomberfishandClaude Opus 5.5 33d45bd071 docs/d3d-webgpu.md: the wire, webgpu.dll and wined3d's WebGPU renderer, as they stand
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_f0a06c8a084b4b2ca4f7f291183d507d
2026-10-14 05:27:24 -04:00
bomberfishandClaude Opus 5.5 dc6ec283b7 docs/d3d-webgpu.md: Direct3D on WebGPU, the plan and the WGSL target's state
wined3d with a WebGPU adapter, shaders through a new vkd3d-shader WGSL
target, webgpu.h over dawn_wire to the page (or native Dawn on the native
host). The WGSL target runs vkd3d's HLSL shader tests on Dawn/Metal: 247
of 283 files clean, 96.6% of 6474 checks. Aero needs DWM besides D3D;
the two routes are written down for later.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_f0a06c8a084b4b2ca4f7f291183d507d
2026-10-14 03:08:34 -04:00
velzie 1873380d91 integ: merge 48f7767a p/split
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c

# Conflicts:
#	shims/browser/js/gex.mjs
2026-10-13 12:09:53 -04:00
velzieandClaude Opus 5.5 eb9b976f13 docs/gexcc.md: the in-place fork that was tried and not landed
feat/inplace-fork (6fe60515) is kept unmerged: correct, but snapshots
740 ms plus restores 226 ms for apt-get update's 11 forks, no win against
pooled Workers on the timed apt pair (edger, inside noise).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-13 11:48:00 -04:00
velzieandClaude Opus 5.5 ba3f4227a2 docs/eject.md: the bundle split's numbers (Paint, worldmachine)
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-13 09:19:04 -04:00
velzieandClaude Opus 5.5 d7defdd22a tests/eject/w3-page, record-w3: ranges; the leg checks a split bundle
The leg's and the recorder's servers answer ranges (a split bundle's lazy
files are read 1 MiB at a time). On a split site the leg checks lazy.json
against the store, says how many lazy reads the run made to the window, and
with --placed has Paint's Ctrl+P read printing's DLLs from the store.
docs/eject.md: "The bundle split".

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-13 09:12:43 -04:00
velzieandClaude Opus 5.5 65ea266dcc tests/eject/w3-page: --placed, the bare desktop leaves placed windows to Wine
A caption drag moves Paint by the drag, a border drag past its edge grows
it and one inside shrinks it, and a click on Paint leaves its owned dialog
on top; the first window is where Wine put it, not cascaded.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-13 08:21:07 -04:00
velzie f4008e3398 Merge commit '3f881f07' into p/demo-1013
# Conflicts:
#	shims/browser/js/gex.mjs
#	shims/browser/js/host.mjs
#	shims/browser/src/lib.rs
#	web/src/compositor-worker.js
2026-10-13 07:21:23 -04:00
velzie 2c0fe4554e integ: merge 805423a1 land/wskern (K: wineserver in the gex kernel: doors, session mirror, wakeups, USD, guards, tests/w3 legs)
Conflict: gex-atomic imports, both kept (pub mod rcu; AtomicU64).
2026-10-13 02:07:28 -04:00
velzie bf6dfffa4e integ: merge f03f0896 merge/demo-desktop (C: glxgears xwm id reuse, one launch path, Mesa publish, GL forget, foot configure_bounds/#fit, resize/move/maximize, scene release, VRAM leg)
Conflicts: lib.rs stderr reporting: W's stderr_capture() refactor kept, with C's
rule (warn only when nothing went through; escape non-printables; name stdout or
stderr) moved into it. system-worker.js: W's addMemory(kernel) plus C's dropMemory.
2026-10-13 02:07:20 -04:00
velzie 06a5146b8f Merge branch 'eject/w3' into p/k8-eject
# Conflicts:
#	shims/browser/js/wl-bridge.mjs
#	shims/browser/src/lib.rs
2026-10-13 00:33:29 -04:00
velzie 911ddb3a87 docs: wineserver-kernel §10.2, the kill leg
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
(cherry picked from commit e00046636bbd6c66bd516314bd0e454b49763bee)
2026-10-12 23:58:54 -04:00
velzie 36e91f3dc5 docs: wineserver-kernel §10.2-10.3, the full migration so far and SP doors
Session mirror, wakeups in place, the USD through the door, the in-door
word and poisoning (clients killed with the server), the door context
bug, mspaint click timings per step, and the SP plan.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
(cherry picked from commit 7d8cda37fa44dec54a5c08b334339d9e5912877e)
2026-10-12 23:58:54 -04:00
velzie f3a7e0a0df docs/wineserver-kernel.md: §10.1 Undertale with doors
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
(cherry picked from commit 51ef27bc4d79d1b65e4ce0b79a0c924ba8b1ea17)
2026-10-12 23:58:47 -04:00
velzie 39ebe81929 docs/wineserver-kernel.md: prototype status and first measurements (§10.1)
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
(cherry picked from commit a31854941e3a3f46ee410f6ae558a7c3b02ab709)
2026-10-12 23:58:17 -04:00
velzie c9209cd519 docs/wineserver-kernel.md §9: the user allows a shared runtime-owned server memory in eject
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
(cherry picked from commit 61f0586e9061a1d45e85390e3c9c9ccd1f60ad9c)
2026-10-12 23:58:16 -04:00
velzie 030270459f docs/wineserver-kernel.md: a runtime-owned server memory; W's lock, proxy and termination points
The server memory is created and owned by the runtime with the kernel
module's lifecycle, never a guest mapping, so sharing it is a build
option for eject. The server lock is a robust word waited on through
step 2's slots (SP suspends through JSPI). The pump serves proxied
syscalls from both of its waits, so a door caller waiting on the pump
under the server lock cannot deadlock.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
(cherry picked from commit d8461354092b53ff1d25e84a7a9b941c039a0b54)
2026-10-12 23:58:16 -04:00
velzie 607bce8194 docs: wineserver-kernel.md, the design for wineserver as a door server on its own shared memory
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
(cherry picked from commit 2f598007c29c60248978b294795fc23ffdfdde40)
2026-10-12 23:58:16 -04:00
velzieandClaude Opus 5.5 f07a500ab7 tests/demo/desktop.mjs: foot fits, windows resize, GPU memory per GL client
- fitsLeg: foot from the launcher must open inside the output, at a
  terminal's size in CSS pixels at any dpr.
- resizeLeg: a corner of foot and of the xterm, one on the canvas with room,
  is dragged by CDP pointer events, and the size the client drew must grow.
  For foot, a title double-click must maximize and a second restore.
- {"glcycles": N}: glxgears from the launcher N times, with the card's used
  memory (nvidia-smi) after each exit; it must not grow per client.

docs/gexcc.md §9.2: the GL forget, foot's size, resize and maximize.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-12 20:43:43 -04:00
velzieandClaude Opus 5.5 29384a1701 eject-site: no service worker for PE sites either; the page decodes the bundle and units
The user's no-SW direction covers every gex page. A PE (Noita) site now
ships its page as plain files, packs only the bundle and the units (which
nt.html fetches and decodes itself, pack=), and its launcher checks
isolation and WebGPU, unregisters an older build's worker and opens nt.html
on the build: no install, no reload, no progress bar of its own. sw.js is
deleted.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-12 20:03:08 -04:00
velzieandClaude Opus 5.5 7c47ee497d page: read, write and rt_sigprocmask never take the kernel lock
The lock-free syscall class (docs/kernel-locking.md step 9): read, write,
readv, writev, pread64, pwrite64, lseek and rt_sigprocmask, decided by
number (syscalls::free_class). The page makes the whole call from its
Worker, blocking included, with the same code the kernel runs (FdIo,
sigprocmask). A call that waits:
- parks in the thread's own run state;
- makes its first scheduler turn itself (pick_mine): it finishes the call,
  or registers the slot on the stream's queue.

The idle "why" is per thread and kernel-free (wait_why, HAVE_NET,
FileHandle::is_global_socket). waitq::enter and publish_timer read the
process's signal state, not the kernel. Only the process's end stays the
kernel's (exit_here).

Also deletes 8 sites that read the pid or the ABI (my_pid, compat_abi).
Sites: 183 -> 175.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-12 19:47:32 -04:00
velzieandClaude Opus 5.5 678441dfd4 page: a woken waiter finishes its call with no kernel lock (§3.7 run state)
Each thread's pc, wait, parked call and what that call still owes live
behind an Arc<Mutex<Run>> of their own, which the thread's Worker holds
(MY_RUN). The kernel's per-call leftovers (restore_sigmask, write_blocked,
the accept/recvmsg/transfer retries) are taken out as the call parks, so an
idle turn that finds its wait over finishes the call itself: finish_parked,
the answer into its context, SIGPIPE, the sigsuspend mask and delivery
through sigs::finish. A call the kernel used to redo after its wait is made
again from its instruction instead (in place for a wasm32 program or a
provider). A safepoint's handler frame resumes without schedule. The locked
pick stays for a blocking call's first turn (under its own take), the
compositor pump and the deadlock watch; exit stays the kernel's.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-12 18:15:08 -04:00
velzie 481246ffa4 Merge commit '3a61c3d8' into merge/demo-desktop 2026-10-12 18:13:02 -04:00
velzieandClaude Opus 5.5 993b6339b3 Merge gex master 3a61c3d8 into step/klock-8
Conflicts: proc.rs keeps both the process wait queue and the /proc info;
run.sh's PAGE_PROGRAMS has the signal programs and clock-monotonic;
runtime.js passes the kernel with wl-memory. EpollSet::with_watches (a
fork's copy) is now built on new(): its own queue, each watch chained
again as a waiter collects it.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-12 18:05:27 -04:00
velzieandClaude Opus 5.5 6262ce71a2 Merge master 3a61c3d8 into eject/w3
Conflicts: wl-bridge.mjs (the publish word stays at 2, the output scale
moves to 3), compositor-worker.js (both the publish flag and the turn
count), runtime.js (master's output scale under the compositor-feature
guard; hostxcount with the kernel argument to addMemory).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-12 18:03:18 -04:00
velzieandClaude Opus 5.5 106b547c0a eject W3: no service worker; the page decodes the bundle and units and moves one copy to pid 1
The ejected mspaint site ships no sw.js and never reloads. nt.html's pack=
names the site's pack.json; a packed file (the bundle, the units) is
fetched as FILE.zst?v=BUILD and decoded in the page with zstddec,
straight into the buffer that is then moved to pid 1. The page itself is
plain files (80.7 MB download for mspaint, from 75.4 MB). The launcher
goes straight to nt.html when it is cross-origin isolated, and says which
headers to send when it is not; a W3 site gets serve.mjs and _headers.

pid 1's Worker lets go of the moved bundle by moving it on to a closed
MessagePort: transfer(0) detaches V8's view but a buffer that arrived by
postMessage stays resident until the Worker collects, which an idle guest
Worker never does (Chromium on gooner: 513 MiB renderer RSS either way
with a 400 MiB buffer, 112 MiB moved on).

Memory, renderer PSS on worldmachine (mspaint, mem probe): peak 3.76 GiB
with this, from 4.33 GiB with the service worker (s-ej3) and 6.98 GiB for
the s-demo6 page; at the title 3.24 GiB from 3.86 GiB. The bundle's
459 MiB second copy and the service worker's 236 MiB of decoded chunks
are gone.

tests/eject/w3-page.mjs: no sw.js, no registration, one load each of
the launcher and nt.html.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-12 17:08:25 -04:00
velzieandClaude Opus 5.5 f67d8551c8 kernel, page: signal words per thread; a safepoint asks and delivers without the kernel lock
Signals is the process's ProcSig (dispositions behind an RwLock, the
shared pending word, the interval timers with an atomic earliest
deadline) and the running thread's ThreadSig (pending and mask as atomic
words). Switching threads swaps an Arc; save_thread/load_thread are gone.

Each page Worker holds its own thread's ThreadSig (sigs.rs). A safepoint
asks whether a signal would do something, collects the inbox, fires due
timers and builds the handler frame with no kernel lock and no hints:
SIGNAL_SEEN, LOCAL_SIGNALS, TIMERS_ARMED and the 64th-safepoint sweep are
deleted, with the locked check and the locked delivery. The handler's
start reaches schedule through HANDLER_AT. waitq's idle turn asks the
signal state instead of the hints.

- The proc table's signal sequence moves after the inbox bit is set
  (it moved before, which the sweep hid).
- A delivery claims its signal with one fetch_and before building the
  frame, and collecting raises each signal once with its sender: two
  raises let a lock-free deliverer take a process-directed signal twice.
- thread-signals' page failure was the test's 100 ms sleep (a page starts
  a thread's Worker later); it hands off under the mutex now.
  close-while-reading waits for its readers. New signal-storm: targeted
  pthread_kill to spinning threads, a shared signal taken exactly once,
  masks respected. All three in PAGE_PROGRAMS.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-12 16:47:31 -04:00
velzieandClaude Opus 5.5 1ec93bd669 xwm: forget a destroyed window's id; launcher starts programs as a shell does
glxgears ran at about 45 fps with no window whenever it was not the first
X client to use its window id: one typed in the xterm after one from the
launcher, or the reverse. The window manager kept the set of windows it had
Composite-redirected and never removed one. The X server gives a new client
the id a gone client had, so the new window was taken for already redirected
and never was, and rootless Xwayland makes no wl_surface for a window that
is not redirected. Traced on edger with ?wltrace=1: the second client
connected, the window manager got its events, and no surface was ever made.
DestroyNotify now drops the id from the redirected set and from the pending
pairings. Unit test: a_window_id_used_again_is_redirected_again (fails
without the fix).

The launcher no longer starts the host's Mesa before a GL item (startGl).
Every program, launched or typed, starts it with its first GL request
(runtime.js glLazy), so a launch runs the same command a shell would, in
the session's environment. The other difference was setsid and the log
file, which only keep the program off pid 1's terminal.

web/build-all.sh: the Xwayland/hostwl rebuild key now covers
crates/gex-wayland and crates/gex-xwm, which hostwl is built from. Before,
a change to either alone shipped the old hostwl.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-12 16:31:22 -04:00
velzieandClaude Opus 5.5 7bc51204aa hostx: free the X server's pixel pools once nothing refers to them
Every pool the page's Xwayland made stayed allocated for good. Xwayland
drops a window buffer unused for a second and makes a new pool, so an xterm
printing a line a second kept about 0.9 MB per line.

A pool now counts its references: the server's descriptor, its mappings
(gex_shm_unmap in web/xwayland/gexos.c now calls shmUnmap; before it was a
no-op), and the compositor's handles. shims/hostwl gives a handle back
(host_release) once Client::fds_in_use no longer names it: no wl_shm_pool,
no wl_buffer, and no surface showing pixels from it. A surface keeps its
shown pool, because the buffer is released at commit and may be destroyed
while still on screen. With no reference left, hostx frees the pixels once
the page has acked a scene published after the drop (WlProxy.generation and
drawnGeneration), so a frame already on its way is never read from freed
memory. Keymap pools are never freed: the server does not map them through
shmAddr, so nothing would count their last reader.

The leg is a default leg of tests/demo/desktop.mjs and also the step
{"pools"}. The xterm prints a line a second for 12 s, and the X server's
live pools (?hostxcount=1 pools=N, now always on in the test) must not grow
by more than 2. On edger, with freeing disabled: 4 then 14, FAIL. With it:
4 then 4, at dpr 1 and 2. Unit test:
a_descriptor_is_in_use_while_a_surface_shows_its_pixels. The SP Xwayland
(web/build-all.sh --sp --x-only) builds.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-12 14:41:13 -04:00
velzieandClaude Opus 5.5 636f16ce5c eject: W3 pages (Wine as wasm32) and feature selection; mem: dirty-only zeroing, bundle moved not shared
gex-eject:
- features.rs: user/eject.json "features" (compositor, gl, multiprocess,
  translation); a feature off that no build can remove fails, naming why.
- w3.rs: gexc eject of a tools/eject/record-w3.mjs recording (w3-session.json:
  the page's launch, the processes, units used and missed, wasm modules) into
  a project (bundle, units, runtime wasm, recording); gexc eject build builds
  the page with GEX_FEATURES_OFF and writes build/web (page, rootfs.tar,
  units, w3.json). web/eject-site.mjs packs it (--strip --prune --dedupe); the
  launcher starts nt.html as recorded. tests/eject/w3-page.mjs is the leg:
  the site reaches its window with the features off really gone.
- gex.mjs: [gex-record] lines (units with keys, processes, wasm modules);
  nt-page: __nt.session.

Memory (mspaint demo, worldmachine probe):
- The shim's exec, load and snapshot-restore paths zeroed whole mappings
  with fill(0), committing every page of reservations nothing had touched
  (78 MiB per Wine process at 10-88 MiB, more in two processes):
  gex_kernel::zero_dirty_bytes writes only pages that are not zero.
- The page's bundle was a SharedArrayBuffer, resident all session beside
  the kernel's copy (459 MiB): now an ArrayBuffer transferred to pid 1's
  Worker, which frees it (ArrayBuffer.transfer(0)) once loaded.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-12 14:38:46 -04:00
velzie 3a61c3d8f9 integ: merge 2dbb6079 merge/demo-desktop (C: desktop demo + procfs/pty/cursor/dpr/hostx fixes) 2026-10-12 13:52:52 -04:00
velzie 7774f70dac integ: merge 08895c02 plan/kernel-locking (W: §5 rewritten as removal) 2026-10-12 13:52:52 -04:00
velzieandClaude Opus 5.5 2dbb607943 hostx: the compositor gets its own handle per pool sent, not the X server's descriptor number
Bug 3 (the xterm not presenting until clicked off and back on). The page's X
server closes a wl_shm pool's descriptor as soon as it has sent it, and its
next pool gets the same number. The compositor was handed the number and
located each buffer at commit time, so a buffer of an older pool resolved to
whichever pool held the number now. Typing into the xterm reuses its two
buffers; with both pools on one number the window showed the frame before
the one drawn, until something made a fresh pool. A cursor pool on the reused
number was too small for the frame, and the commit was dropped. hostx now
mints a handle per descriptor sent, as SCM_RIGHTS gives the receiver its own
descriptor. Guest Wayland clients (foot, Wine, Unity) pass real kernel
descriptors and never took this path.

The leg (a default leg of tests/demo/desktop.mjs, also step {"truth"}) clicks
into the xterm, types at a person's pace, moves the pointer across the window
edge, waits, then compares the X server's copy of the window (xwd through
tests/demo/guest/xsig.py: per-cell dark-pixel counts and a hash of the whole
dark bitmap) with the compositor's output. On edger, without the fix: 0 of 5
rounds equal at dpr 1 (47 dark pixels off, the last character and the
cursor), 0 of 3 at dpr 2 (228). With it: 5 of 5 and 3 of 3 exact.

The layers were measured with ?hostxcount=1 (kept): once a second, the bytes
the X server read from and wrote to each client, its bytes to the
compositor, and its scenes published. With ?wltrace=1 that showed two cursor
pools at one address and xterm buffers located to nothing. Damage and the
present path were ruled out first: forcing full uploads changed nothing, and
every commit changed the composed picture.

Known gap, in docs/gexcc.md §9.2: pool memory is never freed (as before).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-12 13:48:29 -04:00
velzieandClaude Opus 5.5 c69c4e7162 kernel: a pty master reads EIO once every slave has closed, even while the session leader is a zombie
Linux reports the slave side going away to the master as EIO. gex said
end-of-file, and only once the session leader was gone from the process
table: it was in the table as a zombie until its parent waited. A parent
that reads the master until EIO and then calls waitpid (Python's pty.fork,
any terminal emulator) therefore read for ever.

- Pty::master_read answers EIO, not 0, when every slave has closed.
- hangup_is_real asks ProcTable::alive (in the table and not exited)
  rather than exists. The reopen window (a live leader between slave
  descriptors) still reads EAGAIN.

Tests: the pty unit test the_master_reads_eio_once_every_slave_has_closed,
and tests/demo/guest/tty.py, where the master must read EIO within 15 s of
the shell exiting, before waitpid. docs/gexcc.md §9.2 also states the
epoll-across-fork gap: the child gets a copy of the set, not Linux's shared
instance, until W's kernel-locking step 2.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-12 12:44:42 -04:00
velzieandClaude Opus 5.5 08895c0239 docs/kernel-locking.md: §5 as removal, each remaining step a subsystem whose lock is deleted
The user, 2026-10-12: the plan is removal, not fast paths. §5 now says so,
with the progress metric (lock-taking call sites in shims/browser/src, 232
on master f3689d12, and the per-syscall census), what has landed (steps 0
to 5 and 6a), and the remaining steps ordered by the measured wait of the
diag/klock-6e census: clocks, then waits on Linux's wait-queue model (a
slot per thread registered on every watched object, epoll notified by its
objects, no global WAKE re-check), then the fd table, futexes, per-thread
signal state, the memory map, signals and the thread table, lifecycle, and
native. Each says which structures become concurrent and how.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-12 12:42:39 -04:00
velzieandClaude Opus 5.5 3eb213c65b Demo desktop: a desktop shell on gex's compositor, a minimal base, everything else on demand (docs/gexcc.md §9)
One page, web/desktop.html, built stripped by web/build-demo.sh into
web/dist-demo. It opens two windows: an xterm running bash (X11 through the
in-page Xwayland) and a launcher drawn by the page. The base rootfs is 8.3 MB
of zstd for bash and xterm. Launcher items are tar.zst overlays
(tools/gexcc/debian/mkoverlay.py) unpacked into the running kernel, and apt
gets our pool as lazy files. Runtime .wasm ships as .wasm.zst
(web/src/zfetch.js). Measurements are in §9.1.

Shared code this changes, for every page:
- kernel: /proc lists every process (ProcTable info and snapshot through
  the global kernel), and each has stat, status, statm, cmdline and comm. A
  pty leaves FIONBIO and the close-on-exec ioctls to the kernel, which
  fixes libuv (nvim) on a terminal.
- gex-wayland and the shims: wl_output.scale and set_buffer_scale.
  Records carry the buffer and client scales; scale 1 behaves as before.
- compositor: a device-pixel output and decorations scaled by the page's
  scale (1 unless a page passes one). Nearest sampling for 1:1 draws. The
  client's cursor becomes the canvas's CSS cursor on every page (before,
  only in direct present), and no cursor is composited. The present path
  is unchanged: the worker's own WebGPU canvas, driven by its
  requestAnimationFrame.
- runtime.js: wlScale; glLazy starts Mesa on the first guest GL request.
- web/build-all.sh: --x-only and --gl-only, for build-demo.sh.

Fixes from the first users, and the open xterm presentation report, are in
§9.2. tests/demo/desktop.mjs drives the demo. Its cursor and presentation
legs run unless DEMO_LEGS=0.

Squashed from demo/desktop (a6b38999 plus the driver commit) on master
e4c2a2c3. That branch's history also committed web/public/gex-apt (56
.debs of build output) by mistake, and this commit does not carry it.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_ea9f71488b6e448da93d6c2dabf4879c
2026-10-12 12:35:59 -04:00