• Jinoh Kang's avatar
    server: Always prefer synchronous I/O in nonblocking mode. · a115feab
    Jinoh Kang authored
    foobar2000.exe's UPnP Media Renderer component (foo_out_upnp.dll)
    expects that, if a select() call completes successfully with a non-empty
    writefds set, any immediately following send() call on a socket in the
    writefds set never fails with WSAEWOULDBLOCK.
    
    On Wine, the Winsock select() and send() implementations both call the
    Unix poll(2) under the hood to test if I/O is possible on the socket.
    As it turns out, it's entirely possible that Linux poll() may yield
    POLLOUT on the first call (by select) but *not* the second (by send),
    even if no send() call has been made in the meanwhile.
    
    On Linux (as of v5.19), a connected (ESTABLISHED) TCP socket that has
    not been shut down indicates (E)POLLOUT only if the ratio of
    sk_wmem_queued (the amount of bytes queued in the send buffer) to
    sk_sndbuf (the size of send buffer size itself, which can be retrieved
    via SO_SNDBUF) is below a certain threshold.  Therefore, a falling edge
    in POLLOUT can be triggered due to a number of reasons:
    
    1. TCP fragmentation.  Once a TCP packet is split out from a larger
       sk_buff, it incurs extra bookkeeping overhead (e.g. sk_buff header)
       that is counted in sk_wmem_queued alongside application data.
       See also: tcp_fragment(), tso_fragment() (Linux 5.19).
    
    2. Control packets (e.g. MTU probing).  Such packets share the same
       buffer with application-initiated packets, and thus counted in
       sk_wmem_queued.
       See also: sk_wmem_queued_add() callers (Linux 5.19).
    
    3. Memory pressure.  This causes sk_sndbuf to shrink.
       See also: sk_stream_moderate_sndbuf() callers (Linux 5.19).
    
    Fix this by always attempting synchronous I/O first if req->force_async
    is unset and the nonblocking flag is set.
    
    Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53486
    a115feab
sock.c 112 KB