Thanks both. Happy to go either way on the design. Taking the specific points first. On sync vs async (Paul): libcurl uses synchronous non-blocking `send()`, not overlapped writes. I checked current master to be sure: `swrite()` maps straight to `send()` (lib/curl_setup.h), the socket is put in non-blocking mode in `cf_socket_open()` (`curlx_nonblock` plus `SOCK_NONBLOCK`), and `cf_socket_send()` calls `swrite()` and returns `CURLE_AGAIN` on `EWOULDBLOCK`. The multi loop polls the socket for writability and only retries the send once it sees `POLLOUT`. So the stall is the writability check reporting "not writable" while the send buffer still has room, with curl waiting out its poll timeout before retrying a `send()` that would have succeeded. For `async_queue_has_waiting_asyncs()`, agreed with Elizabeth: the synthesized `POLLOUT` goes through `sock_dispatch_asyncs()`, which consumes it to wake a waiting write async before it reaches `select`, so a pending overlapped send is not starved. On guarding for Linux (Elizabeth): the block only runs when the OS withheld `POLLOUT` (`!(revents & POLLOUT)`) while the buffer has room, so it is self-limiting rather than Linux-specific. Where `poll()` already reports writability at the low-water mark (the BSDs and macOS, at `SO_SNDLOWAT`), `POLLOUT` is already set and the block is skipped. That is why I gated on `TIOCOUTQ` rather than `__linux__`. I can note that in the comment. For UDP and the `WS_SOCK_STREAM` check (Elizabeth): a connected UDP socket stays `SOCK_CONNECTIONLESS`, since `connect` only moves to `SOCK_CONNECTED` for non-`DGRAM` types, so `SOCK_CONNECTED` already rules out UDP. I kept the explicit `WS_SOCK_STREAM` to also rule out a connected raw socket, where the `TIOCOUTQ < SO_SNDBUF` reasoning does not hold. Glad to drop it and rely on the state if you would rather. On the larger question: you are right that a poll-time check will not re-wake a `select` already blocked when space frees later, and that driving writability off the write queue is cleaner and closes that gap. For the app-limited synchronous-send loops this targets, curl being the case in front of me, the writability test happens at poll time, so this restores the fast path without that gap biting in practice. That is why I sent it as the minimal change. I am not attached to it. If you would prefer the write_q approach (advertise writable on an empty queue, queue the send, and re-signal waiters on completion, extending the short-write path in `sock_send()`), I am glad to write it. Since that reworks the core send and flow-control path, I would welcome a steer on the shape you have in mind, or I will defer if one of you would rather own it. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11272#note_144505