summaryrefslogtreecommitdiff
path: root/src/9p_io.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-28 17:51:35 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:15 -0300
commit7de6d8304f563023c4a5fa9f8223f9ed626c5f91 (patch)
treec406339964e6af5383d49cf8a23fe26dd8c634fb /src/9p_io.zig
parent9f6de14934df03c2e3d521af78ce2e5d7362cc88 (diff)
downloadpardes-7de6d8304f563023c4a5fa9f8223f9ed626c5f91.tar.gz
pardes-7de6d8304f563023c4a5fa9f8223f9ed626c5f91.zip
Sixteen 9P connections, and the next one is told there is no room instead of being reset
Four slots ran out under scripts plus a mount, and the fifth client was closed without a word, which through a mount looks exactly like a dead session. pardes now serves sixteen, and builds against cloud9 09b77cf, whose runner answers the Tversion of a client it cannot seat with an Rerror "too many connections" and tells pardes, which logs `err - 9p: too many connections`. QUIC keeps its own sixteen and still just closes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/9p_io.zig')
-rw-r--r--src/9p_io.zig23
1 files changed, 20 insertions, 3 deletions
diff --git a/src/9p_io.zig b/src/9p_io.zig
index 6bd03049..8f56ff13 100644
--- a/src/9p_io.zig
+++ b/src/9p_io.zig
@@ -64,7 +64,9 @@ const prefix = "pardes-9p-";
pub const msize = ninep.msize;
-pub const max_conns = 4;
+/// Scripts, a mount and an agent or two at once; each slot holds its
+/// buffers (a few msize) whether used or not.
+pub const max_conns = 16;
extern "c" fn inet_pton(family: c_int, src: [*:0]const u8, dst: *anyopaque) c_int;
@@ -176,6 +178,8 @@ pub const Listener = struct {
stopping: std.atomic.Value(bool) = .init(false),
/// A connection wrote the Restore and has yet to answer it.
restore_writer: std.atomic.Value(bool) = .init(false),
+ /// Clients turned away with every slot taken, since the log last said so.
+ refused: std.atomic.Value(u32) = .init(0),
/// Connections accepted so far, and the count each slot's connection
/// was accepted at: a Restore cuts those accepted before it (`reset`),
/// and a new client in a freed slot has a later stamp. Written on the
@@ -217,6 +221,14 @@ pub const Listener = struct {
/// answers. A request that would change a pane while the editor is out
/// in a syscall mid-step is parked in the engine instead, and retried
/// when the turn is next given up between steps (`wakeParked`).
+ /// On the accepting task, without the turn: counted, and logged with
+ /// the turn (`answerHeld`).
+ fn onRefused(ctx: ?*anyopaque) void {
+ const l = of(ctx);
+ _ = l.refused.fetchAdd(1, .acq_rel);
+ l.kick();
+ }
+
fn onOpened(ctx: ?*anyopaque, conn: *Runner.Conn) void {
const l = of(ctx);
l.accepted[conn.index].store(l.accepts.fetchAdd(1, .acq_rel) + 1, .release);
@@ -331,6 +343,11 @@ pub const Listener = struct {
const l = of(ctx);
if (l.stopping.load(.acquire)) return;
const core = l.core;
+ const refused = l.refused.swap(0, .acq_rel);
+ if (refused != 0) {
+ var why: [64]u8 = undefined;
+ pardes.ctlfs.events.notePath(core, "err -", std.fmt.bufPrint(&why, "9p: too many connections ({d} turned away)", .{refused}) catch "9p: too many connections");
+ }
if (!core.fs.news) return;
core.fs.news = false;
for (&core.fs.opens) |*o| {
@@ -824,7 +841,7 @@ pub fn listen(io: std.Io, gpa: std.mem.Allocator, core: *pardes.Pardes, named: [
l.runner.init(.{
.io = io,
.root = pardes.ctlfs.root,
- .handler = .{ .ctx = l, .serve = Listener.onServe, .opened = Listener.onOpened },
+ .handler = .{ .ctx = l, .serve = Listener.onServe, .opened = Listener.onOpened, .refused = Listener.onRefused },
.greet_timeout_ms = Listener.greet_deadline_ms,
});
const entry_name = if (named.len != 0) named else fallback;
@@ -1356,7 +1373,7 @@ test "Unix TCP and QUIC share one listener through reads writes reconnects and r
}
try testing.expect(l.path().len != 0);
try testing.expectEqual(tcp, l.tcp_address != null);
- try testing.expectEqual(@as(usize, 4), l.runner.conns.len);
+ try testing.expectEqual(@as(usize, max_conns), l.runner.conns.len);
try testing.expect(l.watcher == null);
const port = (if (tcp) l.tcp_address else l.quic_address).?.getPort();
try testing.expect(port != 0);