9c8255f8
refactor: one bounded wait for both side-connection asks
a73x 2026-08-29 10:01
Commit message
src/client/client.zig
| Old | New | ||
|---|---|---|---|
| @@ -1052,6 +1052,24 @@ pub const birth_rows: u16 = 24; | |||
| 1052 | // the tile reads [refused], which is where it stood before. | 1052 | // the tile reads [refused], which is where it stood before. |
| 1053 | const birth_budget_ms: i64 = 3000; | 1053 | const birth_budget_ms: i64 = 3000; |
| 1054 | 1054 | ||
| 1055 | /// One bounded wait on a side connection, shared by every ask that opens | ||
| 1056 | /// its own: false means loop again without reading, `error.Timeout` means | ||
| 1057 | /// the budget is spent. No EINTR arm — `std.posix.poll` retries INTR | ||
| 1058 | /// itself, and its error set holds only failures the fd never recovers | ||
| 1059 | /// from, so waiting the deadline out on one would be a stall, not a wait. | ||
| 1060 | fn awaitFrames(tr: *Transport, deadline: i64) !bool { | ||
| 1061 | const left = deadline - std.time.milliTimestamp(); | ||
| 1062 | if (left <= 0) return error.Timeout; | ||
| 1063 | var fds = [_]std.posix.pollfd{ | ||
| 1064 | .{ .fd = tr.pollFd(), .events = std.posix.POLL.IN, .revents = 0 }, | ||
| 1065 | }; | ||
| 1066 | _ = std.posix.poll(&fds, tr.timeoutMs(@intCast(@min(left, 100)))) catch | ||
| 1067 | return error.Transport; | ||
| 1068 | tr.service(); | ||
| 1069 | // Over QUIC a frame can arrive with the socket never going readable. | ||
| 1070 | return fds[0].revents != 0 or tr.link == .quic; | ||
| 1071 | } | ||
| 1072 | |||
| 1055 | /// Creates `name` on `target` over a connection of its own, then leaves. | 1073 | /// Creates `name` on `target` over a connection of its own, then leaves. |
| 1056 | pub fn birthSession( | 1074 | pub fn birthSession( |
| 1057 | alloc: std.mem.Allocator, | 1075 | alloc: std.mem.Allocator, |
| @@ -1083,20 +1101,7 @@ pub fn birthSession( | |||
| 1083 | try tr.writeFrame(.attach, proto.encodeAttachNamed(&buf, cols, rows, 0, 0, proto.wireName(name))); | 1101 | try tr.writeFrame(.attach, proto.encodeAttachNamed(&buf, cols, rows, 0, 0, proto.wireName(name))); |
| 1084 | const deadline = std.time.milliTimestamp() + birth_budget_ms; | 1102 | const deadline = std.time.milliTimestamp() + birth_budget_ms; |
| 1085 | while (true) { | 1103 | while (true) { |
| 1086 | const left = deadline - std.time.milliTimestamp(); | 1104 | if (!try awaitFrames(&tr, deadline)) continue; |
| 1087 | if (left <= 0) return error.Timeout; | ||
| 1088 | var fds = [_]std.posix.pollfd{ | ||
| 1089 | .{ .fd = tr.pollFd(), .events = std.posix.POLL.IN, .revents = 0 }, | ||
| 1090 | }; | ||
| 1091 | // No EINTR arm: `std.posix.poll` retries INTR itself, and its | ||
| 1092 | // error set holds only failures the fd never recovers from — | ||
| 1093 | // waiting the deadline out on one would be a stall, not a wait. | ||
| 1094 | _ = std.posix.poll(&fds, tr.timeoutMs(@intCast(@min(left, 100)))) catch | ||
| 1095 | return error.Transport; | ||
| 1096 | tr.service(); | ||
| 1097 | // The pump's own disjunct: over QUIC a frame can arrive with the | ||
| 1098 | // socket never going readable. | ||
| 1099 | if (fds[0].revents == 0 and tr.link != .quic) continue; | ||
| 1100 | while (true) { | 1105 | while (true) { |
| 1101 | // Not `Refused`: a read that failed is a transport that | 1106 | // Not `Refused`: a read that failed is a transport that |
| 1102 | // broke, and telling the browser its attach was refused for | 1107 | // broke, and telling the browser its attach was refused for |
| @@ -1163,17 +1168,7 @@ pub fn listSessions( | |||
| 1163 | try tr.writeFrame(.sessions_req, ""); | 1168 | try tr.writeFrame(.sessions_req, ""); |
| 1164 | const deadline = std.time.milliTimestamp() + budget_ms; | 1169 | const deadline = std.time.milliTimestamp() + budget_ms; |
| 1165 | while (true) { | 1170 | while (true) { |
| 1166 | const left = deadline - std.time.milliTimestamp(); | 1171 | if (!try awaitFrames(&tr, deadline)) continue; |
| 1167 | if (left <= 0) return error.Timeout; | ||
| 1168 | var fds = [_]std.posix.pollfd{ | ||
| 1169 | .{ .fd = tr.pollFd(), .events = std.posix.POLL.IN, .revents = 0 }, | ||
| 1170 | }; | ||
| 1171 | _ = std.posix.poll(&fds, tr.timeoutMs(@intCast(@min(left, 100)))) catch | ||
| 1172 | return error.Transport; | ||
| 1173 | tr.service(); | ||
| 1174 | // `birthSession`'s disjunct: over QUIC a frame can arrive with the | ||
| 1175 | // socket never going readable. | ||
| 1176 | if (fds[0].revents == 0 and tr.link != .quic) continue; | ||
| 1177 | while (true) { | 1172 | while (true) { |
| 1178 | switch (tr.readFrame(alloc) catch |e| return oomOrTransport(e)) { | 1173 | switch (tr.readFrame(alloc) catch |e| return oomOrTransport(e)) { |
| 1179 | .incomplete => break, | 1174 | .incomplete => break, |