#52

server: keep an async I/O APC on its issuer when the issuer is about to wait for it

OpenSirDankwants to merge intofrom

On iOS `send_thread_signal` cannot work, so `queue_apc` cannot interrupt a running thread. When a synchronous ioctl completes between the server call that issued it and the wait on its wait handle, the issuing thread is busy rather than waiting. `ios_apc_requeue_target` then looks for another thread of the process waiting in the server and, if there is none, drops the APC; the async is completed with the APC's own status and no data: `STATUS_ALERTED`.

Seen as `GetConsoleMode` failing at random on a valid console handle: kernelbase's `console_ioctl` maps every status it does not know to `STATUS_INVALID_HANDLE`, and the console host answers on another thread of the same process within microseconds. A probe calling `IOCTL_CONDRV_GET_MODE` 400 times in a row got `STATUS_ALERTED` 56 times on stdout, 35 on stdin and 160 on CONOUT$. With this change, 400 successes on each (iPhone 15 Pro, iOS 26).

When the async has a blocking wait handle, the issuer's very next server wait is the one for that async and takes system APCs, so queueing the APC on the issuer is delivered there. The case the existing comment guards against, a thread whose next wait is an in-process one on the very event the I/O will set, is an overlapped operation, which has no wait handle and is unchanged.

🤖 Generated with Claude Code