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.
Right, again I can't think >_>
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 mean, why are we guarding for SOCK_STREAM in the first place? Why shouldn't this also apply to other socket types?
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.
Ultimately it doesn't fix the discrepancy, because our ability to actually *send* from the queue is still going to be throttled by POLLOUT. So I don't think there's a reason to make that change. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11272#note_144857