4/8: ``` +struct async_cancel +{ + struct object obj; /* object header */ + struct event_sync *sync; /* sync object for wait/signal */ + struct list asyncs; /* list of asyncs in the cancel group */ + struct list entry; /* entry in process client_cancels list */ +}; ``` In the original CW bug (unfortunately private) there seem to be two contradictory claims about whether CancelIoEx() should wait or not. Should it? [Also, nobody seems to have ever checked CancelSynchronousIo()?] If CancelIoEx() or CancelSynchronousIo() are indeed supposed to wait, then there's a good chance that they're both supposed to wait for the *same* asyncs if called simultaneously, which means we can't store asyncs in the async_cancel's list like this. We'd need to use an array instead, and keep the asyncs in process->cancelled_asyncs. This is probably easiest to test with ntoskrnl, using asyncs that can't actually be canceled, which means that CancelIo() should wait for them to *actually* complete. ``` if (obj) { - int count = cancel_process_async( current->process, obj, thread, req->iosb ); - if (!count && !thread) set_error( STATUS_NOT_FOUND ); + obj_handle_t wait_handle = cancel_process_async( current->process, obj, thread, req->iosb ); + if (!wait_handle && !thread) set_error( STATUS_NOT_FOUND ); release_object( obj ); } ``` This leaks. Probably we should just squash with 5/8. 5/8: ``` + NtWaitForMultipleObjects( 1, &cancel_handle, FALSE, TRUE, NULL ); + NtClose( cancel_handle ); ``` You can probably make this handle automatically close itself when satisfied, like async handles. ``` + else if (status == STATUS_INVALID_HANDLE) + { + return status; + } + + /* TODO: Add a test for the timing of setting IOSB values? It's tricky + * since we probably have to check from a different thread without using + * win32 IPC for synchronization to avoid syncing on system APC + * execution. */ + io_status->Status = status; + io_status->Information = 0; + return status; ``` I guess it doesn't make a difference here, but more generally the iosb is set on !NT_ERROR(status), so that may be more idiomatic to write instead of checking for STATUS_INVALID_HANDLE specifically. [And regarding that comment, the aforementioned ntoskrnl test would probably work here too.] -- https://gitlab.winehq.org/wine/wine/-/merge_requests/7797#note_112626