summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-10-01 10:45:57 -0300
committerGabriel Schneider <[email protected]>2026-10-01 11:09:59 -0300
commitc5e5db988e59689b44feb42c59090c07687bcd42 (patch)
treecfbe54c55de94676c160d75600393e11d8523bf7 /test
parent25844b54fd08dd9cadff2275f2161ee5dd316395 (diff)
downloadpardes-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.py14
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())