diff options
Diffstat (limited to 'src/detached')
| -rw-r--r-- | src/detached/server.zig | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/src/detached/server.zig b/src/detached/server.zig index 2d7a5238..7d286177 100644 --- a/src/detached/server.zig +++ b/src/detached/server.zig @@ -1056,6 +1056,9 @@ pub const Session = struct { // `Twrite` to `ctl` can `push_spawn`, and `dispatch` is mid-iteration // over a descriptor snapshot when it runs. if (s.ninep) |l| { + // Before the drain, so a slot held by silence is taken back on the + // same frame it expires rather than one drain later. + l.expire(); var pending = false; for (0..fs9_service.max_conns) |i| { const t = l.transport(@intCast(i)) orelse continue; @@ -1431,7 +1434,11 @@ pub const Session = struct { // a pty's — asking for it unconditionally makes every idle socket a // ready descriptor and turns the poll into a spin. if (s.ninep) |l| { - if (l.fd >= 0) { + // `accepting`, not `fd >= 0`: a listener paused after an EMFILE + // must leave the set, or the backlog it could not drain reports + // ready on every poll and spins the core. `nextDue` carries the + // moment it comes back. + if (l.accepting()) { fds[n] = .{ .fd = l.fd, .events = poll_in, .revents = 0 }; src[n] = .ninep_listener; n += 1; @@ -1600,6 +1607,14 @@ pub const Session = struct { } if (s.listener >= 0 and s.accept_paused_ms > now) due = if (due) |d| @min(d, s.accept_paused_ms) else s.accept_paused_ms; + // ...and the 9P listener's own greet deadline, for the reason its + // `expire` gives: four slots is a cheaper denial than thirty-two. + if (s.ninep) |l| { + if (l.nextDue()) |ms| { + const at9 = now + ms; + due = if (due) |d| @min(d, at9) else at9; + } + } const at = due orelse return null; return @intCast(@max(0, @min(at - now, std.math.maxInt(c_int)))); } |
