summaryrefslogtreecommitdiff
path: root/docs/detached.md
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-08-27 15:32:02 -0300
committerGabriel Schneider <[email protected]>2026-08-27 16:15:35 -0300
commitf5927a033f0c83753b5cc004e514568eec8c24f8 (patch)
treee31d0f29aac1d4266c42dac99fcdd0013bfbe64d /docs/detached.md
parent5f4719da21f06b58694d52d354f5fda431ff8543 (diff)
downloadpardes-f5927a033f0c83753b5cc004e514568eec8c24f8.tar.gz
pardes-f5927a033f0c83753b5cc004e514568eec8c24f8.zip
detached: drop /dev/fuse from the poll set once the connection dies
Review fixes to steps 1 and 2, found by an adversarial pass over the committed chain. One is a real bug and the rest are comments that were false. THE BUG. `waitInput` put the FUSE descriptor in the poll set whenever the mount existed, and the `.fuse` arm ignored every revent. Linux's `fuse_dev_poll` answers EPOLLERR once the connection is gone, and POSIX reports POLLERR whatever the events mask asked for -- so an external `fusermount3 -u`, a sysfs abort, or systemd taking /run/user/$UID away at final logout (exactly when a detached session is supposed to keep running) made poll(2) return instantly, forever. The daemon then spun the whole pump at 100% of a core for the rest of its life, and re-offered every parked slot to the core at that rate. Measured on the unfixed commit: 0 CPU ticks over 10 s idle, then 1000 ticks over the next 10 s after unmounting its own mount point. Measured after the fix: 0 ticks over 8 s in the same scenario, process alive and in state S. fuse.zig's own poll thread has carried the equivalent guard all along, which is why the desktop shells never showed this and the daemon did. THE COMMENTS, each checkable and each wrong: * `Source.fuse` said the drain is not done in `dispatch` to avoid re-entering the core. Both `pull_wait_input` and `push_poll_frame` are called from inside `pump`, so either re-enters. The real reason is that `dispatch` is mid-iteration over a SNAPSHOT of the descriptors, and one `push_spawn` replaces a pane's master under it. * `fuse.zig`'s new import said "no cycle". There is a cycle: fs_service imports fuse.zig back and still names `*Fs` in three signatures. * `Transport`'s rationale said tty.zig and gui.zig store one in a struct field. Neither does; all four call sites build it inline. * `deinit` justified its ordering against "as long as the harvest takes". `harvest` is waitpid(WNOHANG) and blocks for nothing. The real reason to go first is that aborting the connection wakes a parked reader while its own shell is still alive to run its exit path. * `harvest` claimed pane shells are the only children this process forks. Since step 1 it also forks `fusermount3`, three times over -- reaped by its own spawner, so the conclusion holds and the premise did not. * docs/detached.md, docs/lsp.md and docs/design.typ still said the daemon implements sixteen of twenty-one methods and mounts no /dev/fuse.
Diffstat (limited to 'docs/detached.md')
-rw-r--r--docs/detached.md15
1 files changed, 7 insertions, 8 deletions
diff --git a/docs/detached.md b/docs/detached.md
index b4dde59c..d849c810 100644
--- a/docs/detached.md
+++ b/docs/detached.md
@@ -255,14 +255,13 @@ Stated rather than papered over:
* **The screen is shared, at the smallest common grid.** Two frontends of
different sizes converge on the smaller; the larger window letterboxes. Same
semantics as tmux.
-* **No LSP, no selection pipe, no `--fs` control filesystem** in a detached
- session. The daemon implements **sixteen** of `Host.VTable`'s **twenty-one**
- methods — FEWER than the tty and SDL shells, which install nineteen each,
- everything but `pull_gpio_toggle` and `push_detach` — and it is the only host
- that implements `push_detach` at all. The five it leaves null divide cleanly.
- Three are real losses: `pull_lsp` and `pull_pipe` want a
- worker pool this deliberately single-threaded loop has not got, and
- `push_fs_reply` wants a `/dev/fuse` this process never mounted. They fall back
+* **No LSP and no selection pipe** in a detached session. The daemon implements
+ **seventeen** of `Host.VTable`'s **twenty-one** methods — fewer than the tty
+ and SDL shells, which install nineteen each, everything but
+ `pull_gpio_toggle` and `push_detach` — and it is the only host that
+ implements `push_detach` at all. The four it leaves null divide cleanly.
+ Two are real losses: `pull_lsp` and `pull_pipe` want a worker pool this
+ deliberately single-threaded loop has not got. They fall back
to the core's in-process defaults rather than failing, so the features are
quiet rather than broken. The other two are not losses at all: there is no
moment "after the frame is on screen" for a process with no screen