diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-30 15:14:00 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:17 -0300 |
| commit | 864407b240b812743d6f57a56daf9706b36fc027 (patch) | |
| tree | f2934c7c82602b456cdbacbe446b7e58b4c2d96e /src | |
| parent | 1d0f8cd158bb47941c0187d32422787c92e8feeb (diff) | |
| download | pardes-864407b240b812743d6f57a56daf9706b36fc027.tar.gz pardes-864407b240b812743d6f57a56daf9706b36fc027.zip | |
pardes --wait for a new name waits on the pane it made, by serial, and a pane closed before it looks is done, not a failure
fs.py's `pardes --wait 'wait new.txt'` failed two runs in three on the
0.0.8 merge. The stress case repeats the test's steps: 4 of 50 failed
under load, each with "pardes: --wait: no pane shows that file". A new
name's launch makes its pane, names it, then found it again by path in
/index. The script had already seen the name, saved and removed the pane
by then, so the lookup missed and --wait exited 1.
Now the launch hands --wait the serial pane/new gave it. After a look,
finding no pane on the file means that pane is already closed, which is
the end --wait waits for: exit 0. The follow with its /index recheck
covers a close in between, as before. Under the same load the stress
case went 0 of 100.
The same load showed a test race too, at fs.py's second Restore. The
exec write is answered before the hang-up, but the client's clunk after
it can meet the connection already cut. The test now requires the
answer and tolerates the reset.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.zig | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/src/main.zig b/src/main.zig index 576efc8e..859e6fb3 100644 --- a/src/main.zig +++ b/src/main.zig @@ -102,13 +102,18 @@ const help_text = /// pane `path` landed in (the one it already had, if open), then /log /// followed on one connection until that pane's `del` -- exit 0 -- or the /// connection ends with the session -- exit 1. -fn waitForDel(io: std.Io, gpa: std.mem.Allocator, dial: []const u8, path: []const u8) noreturn { - const first = ninep_io.Client.read(gpa, dial, "/index", "/index") catch std.process.exit(1); - const serial = paneShowing(first, path) orelse { - std.Io.File.stderr().writeStreamingAll(io, "pardes: --wait: no pane shows that file\n") catch {}; - std.process.exit(1); +fn waitForDel(io: std.Io, gpa: std.mem.Allocator, dial: []const u8, path: []const u8, known: ?u32) noreturn { + _ = io; + // The pane this launch made (a name not there yet) is known by its + // serial; one a look opened or went to is found by its file. Found by + // none after the look went there, it was closed already: that is the + // end being waited for, not a failure (a pane closed between the look + // and this read made `--wait` exit 1 before). + const serial = known orelse found: { + const first = ninep_io.Client.read(gpa, dial, "/index", "/index") catch std.process.exit(1); + defer gpa.free(first); + break :found paneShowing(first, path) orelse std.process.exit(0); }; - gpa.free(first); const Wait = struct { gpa: std.mem.Allocator, dial: []const u8, @@ -436,6 +441,7 @@ fn nativeMain(init: std.process.Init) !void { }; break :named std.fmt.bufPrint(&newbuf, "{s}/{s}", .{ std.mem.trimEnd(u8, dir.path, "/"), base }) catch |err| Refuse.with(init.io, word, err); }; + var made_serial: ?u32 = null; if (found_path != null) { var command_buf: [8192]u8 = undefined; const command = std.fmt.bufPrint(&command_buf, "{s}{s}\n", .{ path, word[target.path.len..] }) catch |err| Refuse.with(init.io, word, err); @@ -443,6 +449,7 @@ fn nativeMain(init: std.process.Init) !void { } else { const made = ninep_io.Client.read(arena, parent.dial, "/pane/new", "/pane/new") catch |err| Refuse.with(init.io, word, err); const serial = std.fmt.parseInt(u32, std.mem.trim(u8, made, " \n"), 10) catch |err| Refuse.with(init.io, word, err); + made_serial = serial; var name_buf: [64]u8 = undefined; const name = try std.fmt.bufPrint(&name_buf, "/pane/{d}/name", .{serial}); var line_buf: [4200]u8 = undefined; @@ -466,7 +473,7 @@ fn nativeMain(init: std.process.Init) !void { Refuse.with(init.io, word, err); }; } - if (wait) waitForDel(init.io, arena, parent.dial, path); + if (wait) waitForDel(init.io, arena, parent.dial, path, made_serial); return; } if (positional) |a| { |
