This (hopefully) fixes Farlight 84 randomly hanging during match start.
I think both issues concerned here are pre-existing to both https://gitlab.winehq.org/wine/wine/-/merge_requests/8833 and https://gitlab.winehq.org/wine/wine/-/merge_requests/8782.
So far the game only calls ipv4 IcmpSendEcho2Ex() with an event and NULL apc routine and context, with a 2sec timeout.
Sometimes the thread which called IcmpSendEcho2Ex() will exit before the request is complete. That currently triggers canceling IRP (exiting thread executing async IO will always do so if there is an event provided in async request).
There are two problems with it.
1. Canceling echo request IRP may currently hang nsirpoxy.sys (addressed by the first patch). This happens because icmp_echo_cancel() IRP cancel routine takes global nsiproxy_cs. IRP cancel routine is called by ntoskrnl with irp_completion_cs held, so irp_completion_cs. On some other occasions in nsiproxy.sys (in a generic case not limited to ICMP echo operation) whenever irp_completion_cs and nsiproxy_cs end up being taken together nsiproxy_cs is taken first, so this occasionally hangs. I guess most straightforward fix for that is to use a finer grained critical section in that place. icmp_echo_cancel only needs to be synchronized with listen_thread_proc() exiting from listen function. While patch 2 avoids IRP being canceled at all in this specific case I suppose nsiproxy.sys should still support proper IRP cancel which can happen under different conditions.
2. Thread exit of the thread which called IcmpSendEcho() should not cancel echo request (as the test included in patch 2 shows). The necessary conditions for NtDeviceIoControlFile() not cancelling async on IO queueing thread exit are: - a completion port should be associated; - there should be no event provided to NtDeviceIoControlFile call. Using thread pool's BindIoCompletionCallback() (and then never passing app's event to NtDeviceIoControlFile so the async is not cancelled on thread exit) looks like the simplest solution to me. The alternative would probably be to implement a dedicated thread in iphlpapi to deliver the ioctl requests. That is a bit complicated by the fact that synchronous errors should be returned synchronously from icmp_send_echo() and so far looks less than ideal to me.