On Sat Jul 4 23:45:20 2026 +0000, Paul Gofman wrote:
I think waiting for POLLOUT and immediately sent as soon as it is available, even if Linux signals POLLOUT when some fraction of buffer is already sent, should surely work fine, it is one of the supposed ways to transfer bulk data and should not be the subject for slowdown. As I understand the problem with curl is that it will check for write once, see it is not ready (while there is some 1/3 of send buffer available) and then next time try to send way too late so the speed is low (or if it is not the case, what is the actual problem then, do we understand it?). That should not be the case with async buffer send, there is no benefit of async sending early at 1/3 buffer compared to sending later; in fact, the opposite, we are better off avoiding extra async server roundtrips by writing socket in bigger chunks. It is not like I am completely opposed to originally suggested approach, it is just that it seems to rely on some internal Linux sockets functioning (maybe also soubject to setup / some tunables??) and thus potentially the point of different behaviour across systems. While also not making things work just like Windows. I think the missing piece is that `curl` never uses asynchronous or overlapped sends, so the async buffer path is never involved. Its loop is simply: a synchronous non-blocking `send()`, preceded by a `select()` writability check, with `WSAEventSelect(FD_WRITE)` and `WSAWaitForMultipleEvents()` (1000 ms timeout) as the fallback if `select()` reports the socket as not writable.
On stock Wine, each \~64 KB burst goes like this: * `curl` checks writability with `select()`. The send buffer still has space because the sender is application-limited and never fills it, but Linux only reports `POLLOUT` once the queued data drops below its low-water threshold. Wine therefore reports the socket as not writable. * `curl` falls back to waiting for `FD_WRITE`. That event is only signalled after a `send()` fails with `WSAEWOULDBLOCK`, and that never happens here because the send buffer always has room. I verified this re-arm behaviour on Windows and it matches the MSDN documentation, so Wine is already behaving correctly on that side. * The wait therefore expires after the full 1000 ms. `curl` retries `select()`, sends another burst, and immediately falls back into the same wait. So the problem isn’t that sends happen slightly later than they should. It’s a fixed one-second delay for every \~64 KB burst, which matches the roughly 140 KB/s throughput users report. Under the current Wine behaviour there’s simply no wake-up path that can end that wait early. The discrepancy is in `select()`: on Windows, the pre-check reports the socket as writable whenever a `send()` would accept data, so `curl` never enters the wait in the first place. On the point about relying on Linux internals, I’d actually argue it’s the opposite. The `outq < sndbuf` check is a direct implementation of the Windows contract, namely that a socket is writable if a `send()` would accept at least one byte. It derives that from raw byte counts (`TIOCOUTQ` for queued bytes and `SO_SNDBUF` for the send buffer capacity), rather than relying on Linux’s `poll()` thresholds. That also makes it independent of tunables such as `TCP_NOTSENT_LOWAT`, which affect when `POLLOUT` is reported but not what `TIOCOUTQ` returns. As for whether it behaves like Windows, that’s exactly what the conformance test in this MR checks. It asserts the invariant that “`select()` reports writable if and only if `send()` would accept data”. Running the same test binary gives 0 violations on Windows, about 230 violations out of roughly 660 sends on unpatched Wine (where `select()` reports “not writable” even though `send()` succeeds), and 0 violations on patched Wine. So for the behaviour the test covers, the patch demonstrably brings Wine into line with Windows. On platforms where `TIOCOUTQ` isn’t available, the code is compiled out and the existing behaviour is unchanged. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11272#note_144865