summaryrefslogtreecommitdiff
path: root/test/selfmount.py
Commit message (Collapse)AuthorAge
* An Edit filter that can never be reaped no longer holds the Edit's answer: ↵Gabriel Schneider4 hours
| | | | | | at the limit the command's group is killed and reaped off the answer's path, the stdin writer owning its input, so a filter writing its own ctl with > or >> answers EIO at 10 s instead of hanging; a running Edit keeps its own copies of the names it reports, and the panes it changes refuse Del, delete, rmdir, Undo, Redo, Get and Zerox (busy, EBUSY); e and r say unreadable files in Get's words; the reference says both sides of a filter's own ctl write need <> Co-Authored-By: Claude Opus 5.5 <[email protected]>
* cloud9 re-pinned at fe9772b, whose 9ns invalidates a dead mount's entry off ↵Gabriel Schneider5 hours
| | | | | | the serving thread; selfmount kills a session under a burst of reads of it through the registry mount and checks every read returns Co-Authored-By: Claude Opus 5.5 <[email protected]>
* cloud9 re-pinned at e66b2cf, whose 9ns opens files with ↵Gabriel Schneider7 hours
| | | | | | FOPEN_PARALLEL_DIRECT_WRITES: an Edit filter writing, through a mount, the ctl its Edit came by (without truncating it) answers at once, not after 10 s; selfmount checks it Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Edit's w to a file changed on disk since read is refused once, as Save is (w ↵Gabriel Schneider7 hours
| | | | | | again to overwrite), the rest of an X/'/w written and the refused named; Edit filters get a pane command's environment ($PARDES_MOUNT, $PARDES_9P, $PARDES_PID, $winid); an Edit with no commands runs beside one whose commands run unless it touches a file that one changes, refused busy (EBUSY) as is a second Edit with commands Co-Authored-By: Claude Opus 5.5 <[email protected]>
* An Edit's held write: < | > commands no longer block their 9P connection ↵Gabriel Schneider8 hours
| | | | | | (answered like a held read, so a status read or a filter reading the session's own mount runs beside it), a Tflush or hang-up of the write kills the commands' process groups and changes nothing; e loads by Get's way (asked once, clean after, undo puts the name back); ~ in e r w f B; B checks every name first; an Edit that runs commands is a write of its own, refused up front with other lines; Edit's +Errors output keeps the keyboard where it was; X goes in pane order; a refused write open says its errno; the reference's Coming from acme rows say what Get file's undo, failure and directory refusal, Putall's answer, Zerox across Dump and Incl's directories now do Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Every pane pardes spawns gets $PARDES_MOUNT, the session's own directory ↵Gabriel Schneider19 hours
| | | | | | | | | | | | under 9ns --mntgen ($NINE_MOUNT/pardes/<name>), unset when it is not known 9ns says --mntgen with NINE_MNTGEN=1 (cloud9). Under `9ns --unix` the mount is the server it dialled, never this session (its socket does not exist until it starts), so it stays unset there; scripts fall back to `9p -a "unix!$PARDES_9P"`. Nothing is statted: the name comes from the session's socket and the environment. selfmount checks both modes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* `> exec` through a mount no longer hangs the editor, and a close holding a ↵Gabriel Schneider19 hours
| | | | | | | | | | | | | | | | | | last line is answered at once: the line runs at the editor's next step A shell's truncating open of exec (or look, ctl, log, pager) sends a setattr that changes nothing; it waited for the editor to be quiet, and through a 9ns mount that quiet could never come: 9ns answers nothing else on the mount while the setattr is out, and the editor's step may be out reading a pane's file through it. This was the "truncating open of exec hangs, only in selfmount" mystery. Only a truncate of a pane's file or a tag waits now. A close holding a last line with no newline hands it to the editor's step (tree.runClosedLines, beside fillClosedPagers), as a /pager close does, and is answered at once; a refusal is the log's err. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A +Pager keeps its program's colours: the session parses what /pager is ↵Gabriel Schneider19 hours
| | | | written after its directory with ghostty-vt, SGR becomes spans drawn over the plain text, every other escape is dropped, and PagerColor off pages it plain
* A command line runs when its newline comes, or at its open's close, never ↵Gabriel Schneider20 hours
| | | | | | | | | | | | | | | | because a write was short: a long line cut by a mount is one line A write shorter than its message, and not a multiple of 4096, was taken as whole, its tail a line. 9ns cuts a FUSE write of up to 512 KiB into 65512-byte Twrites, the last one short, so a 600 KiB `Edit ,c/.../` arrived cut and its tail ran as an unknown control message; the 1 MiB refusal failed the same way. Each open now holds a partial line until its newline, or its release, which ends the last line; an Edit block is whole when it closes, as before. A name write with a NUL still fails its write at once. selfmount writes a 600 KiB Edit line and a 1.1 MiB line through a real 9ns mount; building.typ says how lines are cut. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* An open past the session's 64 open records reaches a mount's caller as ↵Gabriel Schneider27 hours
| | | | | | | | | | | EMFILE, "Too many open files": pardes re-pins cloud9, whose 9ns maps the words The refusal's words said too many open files, but 9ns matched none of its needles and handed the shell Input/output error. The re-pinned cloud9's 9ns maps them to EMFILE. selfmount opens the root exec for writing eighty times through the mount and hears EMFILE at the 65th. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* An event record is delivered in pieces to reads shorter than it, so a bash ↵Gabriel Schneider28 hours
| | | | | | | | | | | | | read loop on event works A read shorter than the record waiting was refused EINVAL, and bash's read, a byte at a time on a file it cannot seek in, failed on the first record. A short read now takes the record's front and the next read the rest, as log and pty/data already did and acme allows. A unit test reads two records a byte at a time; selfmount runs a bash read on event through the mount. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* log stats 0, and pardes re-pins cloud9 whose 9ns opens such a file direct ↵Gabriel Schneider30 hours
| | | | | | | | | | | | | | | | and nonseekable: fs.md's follow recipe with cat works through a mount The log stated the length an open would freeze, a length a mount's kernel could take as its end, and a splicing cat read it from the kernel's offset. log now stats 0, as the other streams and generated views do, and the re-pinned cloud9's 9ns opens any file stating 0 FOPEN_DIRECT_IO | FOPEN_NONSEEKABLE. A look at such a file (the mounted index) reads a regular file that will not seek as a stream rather than refusing it as a pipe. selfmount runs the recipe, exec 3<>log; echo follow >&3; cat <&3, through the mount and hears a record made after it started. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A write of a multiple of 4096 bytes holds the partial line it ends with, as ↵Gabriel Schneider30 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | | | one that fills its Twrite does: a burst through a mount no longer runs its cut lines as two commands selfmount's 1000-line burst reported 943 lines, on main too. The log ring was not losing records: a follower opened before the burst heard exactly 943 and no `lost`, and the burst itself exited 1 with `err 1 exec: wrong #args in control message "Msg"`. `seq ... > exec` through the mount arrives as stdio's 4096-byte writes, each shorter than a Twrite. The rule that such a write is whole ran each one's cut last line at once, so both halves of the line ran as commands (hence `exit 127` records). At 12288 bytes the cut left a bare `Msg`, which was refused and failed the write and the rest of the burst. A write of a multiple of 4096 bytes is where a writer's buffer (stdio, a page cache) filled, so it may go on: its unended tail now waits for the next write or the close, like one that fills its Twrite. `printf Save > exec` stays whole at once. fs.md says so, the 9P fuzzer's model of served lines follows it, and a unit test cuts a `Msg` at 4096 bytes. A follower does not lose records silently: a ring that outruns one already reads it `lost N` first (documented, tested). selfmount now follows the log from before the burst, so it checks every line heard once, in order, or a loss said, not a fresh open of a 64 KiB ring. It passed 3 in 3 and joins the gates with the new 9ns. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A connection holds up to 128 reads, the next refused "too many reads ↵Gabriel Schneider30 hours
| | | | | | | | | | | | | | | | | | | waiting: 128", and a mount beside 40 held event reads still answers Two limits met. pardes parked 32 reads per connection and refused the next with EAGAIN's C string, "Resource temporarily unavailable". 9ns kept 32 tags and 31 workers, each pinned by a held read. So 31 followers through one mount took every worker, and `cat layout` then queued for ever: the whole mount deadlocked. cloud9 (705be665, pushed to sr.ht and pinned here) now refuses in words past the cap. Its 9ns window is 256, so a mount always has workers past what pardes holds. pardes raises its cap to 128. fs.md documents the limit beside held reads. selfmount.py holds 40 event reads through the mount and reads layout beside them. It times out with the 9ns installed before this change and passes with the new one. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A command line cut across writes runs once whole, and look/exec answer per openGabriel Schneider30 hours
| | | | | | | | | | | | | | | | A mount cuts a write at its message size, and each piece ran on its own: a line cut at the boundary ran as shell commands and a 50 KB Edit block broke. An open of look, exec, tagexec, any ctl or a column's exec now keeps an unfinished last line, or an Edit block still open, until its next write or its release, and never runs a fragment. The same open record holds what its last write touched, which a read on it answers (as /net/tcp/clone does); an open that never wrote reads the session's last as of its open. A release that runs a held line waits for quiet and counts as a change; a clicked line with a control character is still refused at its write. Tested in unit tests, fs.py (python client, 8 KiB) and selfmount.py (the kernel mount, a 1000-line seq burst and a 50 KB Edit block). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The tree serves the layout: /layout, /tag and /col/<n>/tagGabriel Schneider30 hours
| | | | | | | | | | | | | A script could not see where the panes sit or edit the tags a person clicks in. /layout lists each column, its index, x and width in cells, current or not, empty or full, and its panes' serials, then the active column; /tag is the workspace tag and /col/<n>/tag a column's, read and written as a pane tag is (one line: a newline written in is a space, and a truncating write drops the one ending it); /index's lines end with the pane's column; the log says newcol <n> and delcol <n>. acme serves no column files, and the docs say so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Answer 9P on the connection's task, so a session can open its own treeGabriel Schneider30 hours
The editor's loop was the only thing that could answer a 9P request, which made the editor's own syscalls through a mount of its own tree -- a Look at /mnt/9p/pardes/<me>/anything under a `9ns --mntgen` view, a Save into it -- requests only the blocked loop could serve. The name-based refusal that followed (ownMountSuffix) and the in-process routing of a mount of oneself (Client.sameSession) were patches over that, and both are gone, with the mailbox that shipped every request to the editor's thread. One rule replaces them, `pardes.turn`: the core is single-threaded, the editor's thread has the turn by default and gives it up in two kinds of gap -- while it waits for input and while a step of it is out in a host syscall -- and a cloud9 connection task takes it in those gaps to answer. `out` counts the steps that are out, from any thread: while one is, the core reads consistently but that step still holds pointers into it, so a request that would change a pane (a write, a truncation, an rmdir) is parked in the engine and retried when the turn is next given up with nothing out, and the editor's own wake waits for the count to reach zero. It is never a write of its own that a step waits on out there -- writes come from a shell performing a save between steps -- so a parked request is never the syscall's own, and making a pane or rendering a screen need not park: every yield sits before its step's mutation, so the layout and the surface are whole under it. A changing request that queued effects is answered once the editor has performed them (`echo Save > exec` returns with the file written, as acme's `put` does), and it settles the way a step does, because without that a /log reader waited for the user's next keystroke. Every host syscall on a user path has to give the turn up, not fs.zig's alone: the first end-to-end run hung in `inotify_add_watch` performing the new pane's watch effect. PDFs and images are read whole at open, so no draw goes out into the host. The core's allocator takes its fixed buffer through the lock-free interface, since a connection task allocates while the editor's thread is out in a syscall that allocates too. A Restore puts the replacement in first and releases every task waiting on the old core. cloud9 (pinned at eb1a104) parks an open, a truncating wstat, a clunk and a remove on `again`, not only reads and writes, and answers a parked job whose fid was clunked without asking the backend. Verified: test/selfmount.py runs the editor under `9ns --mntgen` and Looks at, reads and Saves its own tree through the mount; a unit test pins that a change parks while the editor is out mid-step and lands when it rests, while a read is answered in the window. 9P over the Unix socket against a tty session, same machine, Debug builds: a read of /index 278us -> 61us, a truncating body write 1184us -> 609us, exec Save 718us -> 583us; the gesture benchmark is unchanged (geometric mean 0.997 over 53 cells). Also from the reviews: a notice chip over an image or PDF pane was painted out by the picture drawn after the cells, so pictures give up the rows; in the GUI a tree-sitter context band painted over the chip, so body layers are emitted first; a message is one row of printable text, its 256-byte cut never leaves half a glyph, and one wider than its pane keeps its tail (the file name, the reason) rather than its head. Co-Authored-By: Claude Fable 5.1 <[email protected]>