https://gitlab.synchro.net/main/sbbs/-/issues/1197#note_9690
### Root cause of the `-w8192` slowness (the "related, not fixed here" item)
Diagnosed. It is a real stall, not a benchmark artifact — it reproduces over a
direct socketpair with no relay in the middle.
**Symptom:** with the transmit window equal to the block size (`-8 -w8192`, and the same whenever the block-size ramp reaches the window), the transfer advances
**exactly one window per second**. Data flows in bursts separated by 1-second silences.
**Mechanism (confirmed by strace of both ends + single-clock wire capture):**
1. With a one-block window, every data subpacket fills the window, so after each
block the sender must wait for that block's ZACK before sending the next.
2. `sexyz` sends through a producer/consumer ring: the protocol thread queues
the subpacket, a separate `output_thread` drains it to the socket. When the
protocol thread finishes a subpacket it calls `zmodem_flush()`, but `sexyz`'s
flush callback is a no-op (it only `fflush(stdout)`s, and only in stdio mode).
3. So the protocol thread starts *waiting for the ZACK* while the subpacket's
**terminator** (`ZDLE ZCRCQ CRC`, ~6 bytes) is still sitting in the output
thread's linear buffer, not yet written. The receiver has the 8192 data bytes
but not the terminator, so it cannot see the subpacket boundary and does not
ACK. Its `read()` blocks — measured at `<1.001374>`.
4. Both sides now wait on each other. The sender's back-channel poll times out
after **1 second**, it reads the next file block and queues it, and *that*
write finally pushes the stuck terminator onto the wire. The receiver then
completes the previous subpacket and ACKs it — one second late. Repeat.
`-w32768` (and larger) hides this because the window holds 2–4 blocks, so the asynchronous ACKs for earlier blocks keep the window open and the sender never actually blocks on the not-yet-flushed terminator.
**Confirmation:** replacing the no-op `flush()` with one that waits for the output thread to be genuinely idle (ring empty **and** its linear buffer written)
takes `-8 -w8192` from a crawl to **1.72 MB/s**. That is proof of the cause, but
not a shippable fix on its own — waiting on every subpacket serialises the producer and consumer and cuts streaming throughput roughly in half (11.6 → 4.5
MB/s). A real fix wants an event the output thread signals when fully drained, waited on only where the protocol is about to block for a response — which is the same "flush actually reaches the wire" work the sender redesign in #1195 needs. Tracking the fix there.
*Note by Claude (Anthropic).*
--- SBBSecho 3.37-Linux
* Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)