diff options
| author | Gabriel Schneider <[email protected]> | 2026-10-01 10:45:57 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 11:09:59 -0300 |
| commit | c5e5db988e59689b44feb42c59090c07687bcd42 (patch) | |
| tree | cfbe54c55de94676c160d75600393e11d8523bf7 /test | |
| parent | 25844b54fd08dd9cadff2275f2161ee5dd316395 (diff) | |
| download | pardes-c5e5db988e59689b44feb42c59090c07687bcd42.tar.gz pardes-c5e5db988e59689b44feb42c59090c07687bcd42.zip | |
`> exec` through a mount no longer hangs the editor, and a close holding a 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]>
Diffstat (limited to 'test')
| -rw-r--r-- | test/selfmount.py | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/test/selfmount.py b/test/selfmount.py index 57dfffa8..8d78487d 100644 --- a/test/selfmount.py +++ b/test/selfmount.py @@ -196,6 +196,18 @@ def run(binary): while (said := client.read(f'/pane/{paged[0]}/body')) != b'red\n' and time.monotonic() < deadline: time.sleep(.05) check(said == b'red\n', f'its body is the plain text ({said!r})') + # `>`'s truncate of exec changes nothing and waits on nothing, + # and a last line with no newline runs once its open closes, at + # the editor's next step, the close answered at once. Either + # waiting on the editor hung: 9ns answers nothing else on the + # mount while a setattr or a clunk is out, and the step may be + # out reading a pane's file through it (the mounted index above). + got = run(f"for i in $(seq 40); do printf 'Msg held-%d' $i > {mount}/exec || exit 9; done\n".encode()) + deadline = time.monotonic() + 5 + while 'held-40\n' not in (log := client.read('/log').decode()) and time.monotonic() < deadline: + time.sleep(.05) + check(got == '0' and all(f' held-{i}\n' in log for i in range(1, 41)), + f'40 closes holding a last line each through the mount, all answered, every line run ({got!r})') # Forty event reads held through the mount, a follower each, and # the mount still answers the rest: 9ns keeps workers past what # the editor holds (128), so `cat layout` is not queued behind @@ -225,8 +237,6 @@ def run(binary): f'a bash read loop on event reads a whole record ({got_line!r})') # Past the session's 64 open records (write opens of exec take # them too) an open is refused EMFILE, "Too many open files". - # (>> here: a truncating open of exec through the mount can - # hang, reported, not yet understood.) many = Path(f'/tmp/{name}.many') ran = run((f"timeout 10 bash -c 'for i in $(seq 80); do exec {{fd}}>>{mount}/exec || exit 9; done' 2> {many}; " f"st=$?; echo rc=$st >> {many}; exit $st\n").encode()) |
