https://bugs.winehq.org/show_bug.cgi?id=52401
--- Comment #1 from Jinoh Kang jinoh.kang.kr@gmail.com --- I forgot that special (kernel) APCs can be delivered at any time.
In this case, steps 7 - 9 of the scenario are slightly modified:
1. The socket's incoming buffer is initially empty.
2. Client: The application calls WSARecv(). In sock_recv(), try_recv() fails with STATUS_DEVICE_NOT_READY; therefore, a deferred Async is queued to the server. WSARecv() returns with ERROR_IO_PENDING.
3. The socket receives packet [A] in the meantime. The socket's incoming buffer is no longer empty.
4. Client: The application calls WSARecv() again. In sock_recv(), try_recv() succeeds with packet [A]; therefore, an eager Async is queued to the server.
5. The socket receives packet [B] in the meantime.
6. Server: the poll() loop detects this, and calls async_wake_up( &sock->read_q, status ). This causes APC_ASYNC_IO for the deferred Async to be delivered to the client process.
7. Client (SIGUSR1 handler): The client does a server select call. This returns STATUS_KERNEL_APC with APC_ASYNC_IO. The client calls try_recv() (from async_recv_proc), which succeeds with packet [B]. The client process completes the deferred Async with this packet.
8. Server: the wait on the async wait handle is satisfied, causing async_satisified() to be called. This in turn calls async_set_result(), which completes the eager Async (with packet [A]).
9. Client: The client exits sock_recv() and in turn WSARecv(), which reports immediate success.
It appears that my previously suggested solutions 2 and 3 would be useless in this case. Perhaps block any system APCs in the meantime?
If that's undesirable, we're left with solution #1. That shouldn't be too bad though, since the round trip to the server is inevitable anyway. Perhaps we can optimize this path at the server side (instead of doing eager/deferred processing in the user side).
--
Known impacted application: KakaoTalk 3.3.6.2992 (https://appdb.winehq.org/objectManager.php?sClass=version&iId=40551)