diff options
| author | Peter Geissler <peter@haxx.in> | 2026-08-26 16:44:33 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-26 16:48:17 +0200 |
| commit | 9d5f9d2a1c3b8d0948a8efa8443a36847aa2107b (patch) | |
| tree | c56a344009a59970d1e0495ec76568ebf6046275 /include | |
| parent | macos: the kernel still knows, it just spells /proc differently (diff) | |
| download | slosh-9d5f9d2a1c3b8d0948a8efa8443a36847aa2107b.tar.gz slosh-9d5f9d2a1c3b8d0948a8efa8443a36847aa2107b.tar.xz slosh-9d5f9d2a1c3b8d0948a8efa8443a36847aa2107b.zip | |
a client that stops reading must not stop the session
Everything the server said went out through msg_send(), which loops on
sendmsg() until the kernel has taken all of it. That is a blocking write
to whoever is attached. A display whose reader has paused -- C-s at the
terminal, a stopped ssh, a client being swapped -- fills its socket
buffer, and then the *server* sits inside that loop: every other pane,
the config watcher, the control socket and every other connection stop
with it. A session that is supposed to outlive its client hangs on one.
macOS is where this showed up, because its socket buffers are a fraction
of Linux's 64K and it wedges within a screenful rather than after a few
hundred. `make test-live` could not get past the forty-connection probe
in test_session.py: the server was blocked writing to a pty nobody was
draining, so `slosh cmd panes` timed out and took the suite with it.
So connections are non-blocking and output is queued, flushed when
poll() says the socket will take more. The queue is capped: past 4MB we
are not buffering a slow reader any more, we are storing a screen nobody
is looking at, and the connection is dropped -- a display that comes
back reattaches and gets a full repaint, which is what happens after any
detach anyway.
Measured, with a pane running `yes` and a display that never reads:
before, the first control command hung forever; after, 40 of 40 are
answered, the session stays listed, and the server's RSS is flat.
Diffstat (limited to 'include')
| -rw-r--r-- | include/proto.h | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/include/proto.h b/include/proto.h index e6cd42c..67b45f0 100644 --- a/include/proto.h +++ b/include/proto.h @@ -54,7 +54,13 @@ void msg_reader_feed(msg_reader_t *r, const uint8_t *data, size_t len); * until the next call) when a whole message is available. */ bool msg_reader_next(msg_reader_t *r, msg_t *out); -/* Blocking send of one frame. Returns 0 on success, -1 if the peer is gone. */ +/* One frame is a type byte and a 32-bit big-endian length, then the payload. + * The server frames into its own queue (it cannot afford to block on a client + * that has stopped reading), so the size is not private to proto.c. */ +#define MSG_HDR 5 + +/* Blocking send of one frame. Returns 0 on success, -1 if the peer is gone. + * For the client, which has nothing else to be doing while it writes. */ int msg_send(int fd, uint8_t type, const void *data, size_t len); /* $XDG_RUNTIME_DIR/slosh/<name>.sock, or /tmp/slosh-<uid>/<name>.sock. |
