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.]