• src/sbbs3/sexyz.c

    From Rob Swindell (on Windows 11)@VERT to Git commit to main/sbbs/master on Fri Sep 26 14:17:14 2025
    https://gitlab.synchro.net/main/sbbs/-/commit/6bc626bedf028105f520ad56
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    Increment version to 3.1

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Fri Sep 26 18:16:24 2025
    https://gitlab.synchro.net/main/sbbs/-/commit/70a445decf8a4c69f1ac0c65
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    Sanitize the stdio-path of sendbuf()

    Fix what appear to be bugs in the mix-up of the global 'sock', the 's' argument, and FILENO_STDIN versus FILENO_STDOUT.

    This seemed to work anyway since stdout was blocking (would never return EAGAIN/EWOULDBLOCK).

    Just wanted to clean this up before pollifying (related to issue #445).

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Windows 11)@VERT to Git commit to main/sbbs/master on Fri Sep 26 19:38:47 2025
    https://gitlab.synchro.net/main/sbbs/-/commit/fa6202f2a587411b40d3a94d
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    Implement poll (rather than select) support when PREFER_POLL defined

    Attempt to fix issue #445

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Deuc¿@VERT to Git commit to main/sbbs/master on Fri Oct 24 22:27:59 2025
    https://gitlab.synchro.net/main/sbbs/-/commit/929fc7cde612b44a7dbb9489
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    Fix error on systems where poll() is preferred (ie: *nix)

    Broken in fa6202f2a58, after poll() indicates there is data to
    read, recv_buffer() would return a timeout rather than set the
    timeout to zero and retry the recv().

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Windows 11)@VERT to Git commit to main/sbbs/master on Thu Jan 8 03:55:52 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/231233096fde3a7595afcf69
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    Remove glob() usage

    If we really need to expand wildcards in specified transmit path/filenames
    (do we?), there's better ways to do it.

    Increment version to 3.2

    Fix issue #1044

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Thu Jul 23 23:03:46 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/1672d1f70b2d5f2f14c794c4
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    sexyz: batch ZMODEM output into the ring buffer to fix send throughput

    The transmit path fed the output ring buffer one byte at a time via send_byte(), so the protocol thread and the draining output_thread
    ping-ponged over tiny amounts: a 32 MB send made ~2.3 million futex calls
    and ~409 K writes averaging ~84 bytes. lrzsz and SyncTERM, which buffer
    their output, ran several times faster over the same protocol.

    Accumulate escaped output in a per-session buffer and push it into the
    ring one subpacket-sized span at a time (on the zmodem flush callback, or
    when the buffer fills). The output_thread and its asynchronous socket
    draining are kept intact: that asynchrony is what lets the protocol thread service ZRPOS on the back-channel during error recovery, so removing the
    thread (measured) stalled lossy transfers.

    Results, sending to lrz over a localhost socket:
    - 32 MB send: ~2.3 M -> ~12 K futex calls, ~409 K -> ~4 K writes (~8 KB ea)
    - 256 MB steady-state send: ~11 -> ~66 MB/s
    - error-recovery time under injected bit errors: unchanged (~50 s)
    - receiver throughput: unchanged (~130 MB/s)

    The remaining gap to lrzsz (~204 MB/s) is zmodem.c's per-byte send_byte-callback overhead, addressed separately.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Thu Jul 23 23:03:46 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/da546fbe1bd20ff1754e49b6
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    Revert "sexyz: batch ZMODEM output into the ring buffer to fix send throughput"

    This reverts commit 4e671c75640ccf8248ea9b3822df2d0a08f4f6c9.

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Fri Jul 24 23:28:15 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/34af5f34b57436e1430bdf80
    Modified Files:
    src/sbbs3/sexyz.c
    Log Message:
    sexyz: buffer the ZMODEM streaming send path (#1195)

    The send bottleneck was never the two output threads or the ring -- it
    was feeding the ring one byte at a time. send_byte() took the ring mutex
    twice per byte while output_thread hot-looped on it, so a 256 MB send
    cost 44 CPU-seconds and 1.46 million voluntary context switches and
    topped out near 11 MB/s on localhost.

    Accumulate bytes into a 4 KB buffer and hand whole spans to the ring
    instead. The two-thread architecture, flow control and error handling
    are all unchanged; the producer just stops trickling. A 256 MB send now
    runs at ~115 MB/s using 0.85 CPU-seconds and 64 K context switches -- the
    same throughput a single-threaded rewrite would give, for a fraction of
    the change and none of the risk.

    Buffering only applies to full ZMODEM streaming. A transmit window or segmented mode (-w, -s) depends on the receiver's acks flowing back as
    data is sent; bursty buffered output would fill the window before any ack returns and stall the transfer, so those modes fall through to the
    original byte-at-a-time path and are byte-for-byte unchanged.

    A fast streaming sender also fills the socket's auto-tuned, possibly multi-megabyte send buffer, so a single line error would cost a ZRPOS retransmission of everything in flight and break error recovery. Bound SO_SNDBUF to the ring size to cap the in-flight backlog (streaming only --
    a window already bounds it, and a socket buffer smaller than the window
    would fight it). This is applied outside the stdio guard so it takes
    effect for a piped socket as well, and [sockopts] can override it for a
    high bandwidth-delay link.

    Verified against lrz over the bench harness: 256 MB streaming MATCH at
    ~115 MB/s; the 3x error-injection gate passes 5/5; windowed (-w8192
    through -w65536), segmented (-s) and the receive path are unchanged from before; an 8 MB transfer over a 25 ms link matches the byte-at-a-time
    sender (both link-bound). No zmodem.c change, so SyncTERM is untouched
    (and it already has a buffered send path of its own).

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    ■ Synchronet ■ Vertrauen ■ Home of Synchronet ■ [vert/cvs/bbs].synchro.net