If the server detects that an I/O request could be completed immediately (e.g. the socket to read from already has incoming data), it can now return STATUS_ALERTED to allow opportunistic synchronous I/O. The Unix side will then attempt to perform I/O in nonblocking mode and report back the I/O status to the server. If the operation returns e.g. EAGAIN or EWOULDBLOCK, the client can opt to either abandon the request (by specifying an error status) or poll for it in the server as usual (by waiting on the wait handle).
Without such mechanism in place, the client cannot safely perform immediately satiable I/O operations synchronously, since it can potentially conflict with other pending I/O operations that have already been queued.
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com ---
Notes: REVIEWERS: The mention of the set_async_direct_result request comes in the next patch where it is introduced.
v2 -> v3: set async->alerted = 1 v3 -> v4: unchanged v4 -> v5: - edit comments - remove irrelevant word in commit message (signal_wait_async) - async_handoff(): don't check for async->pending in new code path - async_handoff(): use async_terminate() directly in new code path
server/async.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/server/async.c b/server/async.c index 7aef28355f0..97b3b9fc10a 100644 --- a/server/async.c +++ b/server/async.c @@ -338,6 +338,30 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_ return async->wait_handle; }
+ if (get_error() == STATUS_ALERTED) + { + /* give the client opportunity to complete synchronously. after the + * client performs the I/O, it reports the result back to the server. + * if it turns out that the I/O request is not actually immediately + * satiable, the client may then choose to re-queue the async by + * reporting STATUS_PENDING instead. + * + * since we're deferring the initial I/O (to the client), we mark the + * async as having unknown initial status (unknown_status = 1). Note + * that we don't reuse async_set_unknown_status() here. This is because + * the one responsible for performing the I/O is not the device driver, + * but instead the client that requested the I/O in the first place. + * + * also, async_set_unknown_status() would set direct_result to zero + * forcing APC_ASYNC_IO to fire in async_terminate(), which is not + * useful due to subtle semantic differences between synchronous and + * asynchronous completion. + */ + async->unknown_status = 1; + async_terminate( async, STATUS_ALERTED ); + return async->wait_handle; + } + async->initial_status = get_error();
if (!async->pending && NT_ERROR( get_error() ))