From: Jinoh Kang jinoh.kang.kr@gmail.com
removetodo --- server/async.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+)
diff --git a/server/async.c b/server/async.c index fbd7c37717d..7f5ea3141b8 100644 --- a/server/async.c +++ b/server/async.c @@ -34,6 +34,30 @@ #include "process.h" #include "handle.h"
+enum async_state +{ + /* The I/O operation has just initiated, or initial status is known. */ + ASYNC_INITIAL, + + /* The initial status is not known yet. It will be determined by the client or winedevice.exe. */ + ASYNC_UNKNOWN_STATUS, + + /* The I/O operation is being processed by the wineserver or winedevice.eze. */ + ASYNC_IN_PROGRESS, + + /* The I/O operation is being processed by the client. */ + ASYNC_ALERTED, + + /* The I/O operation has finished synchronously but not been acknowledged by the client. */ + ASYNC_FINALIZING_SYNC, + + /* The I/O operation has finished asynchronously but not been acknowledged by the client. */ + ASYNC_FINALIZING_ASYNC, + + /* The I/O operation has finished and the result has been acknowledged by the client. */ + ASYNC_COMPLETED +}; + struct async { struct object obj; /* object header */ @@ -49,6 +73,7 @@ struct async struct iosb *iosb; /* I/O status block */ obj_handle_t wait_handle; /* pre-allocated wait handle */ unsigned int initial_status; /* status returned from initial request */ + enum async_state state; unsigned int signaled :1; unsigned int pending :1; /* request successfully queued, but pending */ unsigned int direct_result :1;/* a flag if we're passing result directly from request instead of APC */ @@ -109,6 +134,30 @@ static int async_signaled( struct object *obj, struct wait_queue_entry *entry ) { struct async *async = (struct async *)obj; assert( obj->ops == &async_ops ); + switch (async->state) + { + case ASYNC_INITIAL: + case ASYNC_UNKNOWN_STATUS: + assert( async->signaled == 0 ); + break; + case ASYNC_FINALIZING_SYNC: + /* If direct_result, the client will "wait" on the async to signal completion. */ + assert( async->signaled == async->direct_result ); + break; + case ASYNC_IN_PROGRESS: + case ASYNC_ALERTED: + case ASYNC_FINALIZING_ASYNC: + /* If nonblocking, the client will "wait" on the async to close it. */ + assert( async->signaled == (!async->blocking) ); + break; + case ASYNC_COMPLETED: + /* If there is an open async handle, notify the waiter of completion. */ + assert( async->signaled == 1 ); + break; + default: + assert( 0 ); + break; + } return async->signaled; }
@@ -162,16 +211,54 @@ static void async_destroy( struct object *obj )
static int async_terminated( const struct async *async ) { + switch (async->state) + { + case ASYNC_INITIAL: + case ASYNC_IN_PROGRESS: + assert( async->terminated == 0 ); + break; + case ASYNC_UNKNOWN_STATUS: + case ASYNC_ALERTED: + case ASYNC_FINALIZING_SYNC: + case ASYNC_FINALIZING_ASYNC: + case ASYNC_COMPLETED: + assert( async->terminated == 1 ); + break; + default: + assert( 0 ); + break; + } return async->terminated; }
static int async_alerted( const struct async *async ) { + switch (async->state) + { + case ASYNC_IN_PROGRESS: + case ASYNC_FINALIZING_SYNC: + case ASYNC_FINALIZING_ASYNC: + case ASYNC_COMPLETED: + assert( async->alerted == 0 ); + break; + case ASYNC_INITIAL: + /* initial status set from set_async_direct_result */ + assert( async->alerted == 1 ); + break; + case ASYNC_UNKNOWN_STATUS: + case ASYNC_ALERTED: + assert( async->alerted == 1 ); + break; + default: + assert( 0 ); + break; + } return async->alerted; }
static int async_unknown_status( const struct async *async ) { + assert( async->unknown_status == (async->state == ASYNC_UNKNOWN_STATUS) ); return async->unknown_status; }
@@ -181,12 +268,41 @@ void async_terminate( struct async *async, unsigned int status ) struct iosb *iosb = async->iosb;
if (async_terminated( async )) return; + assert( async->state == ASYNC_INITIAL || async->state == ASYNC_IN_PROGRESS ); + + if (status == STATUS_ALERTED) + { + if (async->direct_result) + { + assert( async->unknown_status ); + async->state = ASYNC_UNKNOWN_STATUS; + } + else + { + assert( !async->unknown_status ); + async->state = ASYNC_ALERTED; + } + } + else + { + if (async->state == ASYNC_INITIAL) + async->state = ASYNC_FINALIZING_SYNC; + else + async->state = ASYNC_FINALIZING_ASYNC; + }
async->terminated = 1; if (async->iosb && async->iosb->status == STATUS_PENDING) async->iosb->status = status; if (status == STATUS_ALERTED) async->alerted = 1;
+ if (async->state == ASYNC_FINALIZING_SYNC ? async->direct_result : + (async->state != ASYNC_UNKNOWN_STATUS && !async->blocking)) + { + async->signaled = 1; + wake_up( &async->obj, 0 ); + } + /* if no APC could be queued (e.g. the process is terminated), * thread_queue_apc() may trigger async_set_result(), which may drop the * last reference to the async, so grab a temporary reference here */ @@ -283,6 +399,7 @@ struct async *create_async( struct fd *fd, struct thread *thread, const async_da async->queue = NULL; async->fd = (struct fd *)grab_object( fd ); async->initial_status = STATUS_PENDING; + async->state = ASYNC_INITIAL; async->signaled = 0; async->pending = 1; async->wait_handle = 0; @@ -319,10 +436,13 @@ void async_set_initial_status( struct async *async, unsigned int status ) { async->initial_status = status; async->unknown_status = 0; + if (async->state == ASYNC_UNKNOWN_STATUS) + async->state = ASYNC_INITIAL; }
void set_async_pending( struct async *async ) { + assert( (!async->terminated) == (async->state == ASYNC_INITIAL || async->state == ASYNC_UNKNOWN_STATUS) ); if (!async->terminated) async->pending = 1; } @@ -330,6 +450,8 @@ void set_async_pending( struct async *async ) void async_wake_obj( struct async *async ) { assert( !async_unknown_status( async ) ); + assert( async->state == ASYNC_INITIAL ); + async->state = ASYNC_IN_PROGRESS; if (!async->blocking) { async->signaled = 1; @@ -415,6 +537,8 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_ } else { + assert( async->state == ASYNC_INITIAL ); + async->state = ASYNC_IN_PROGRESS; async->direct_result = 0; async->pending = 1; if (!async->blocking) @@ -470,6 +594,8 @@ void async_request_complete_alloc( struct async *async, unsigned int status, dat /* mark an async as having unknown initial status */ void async_set_unknown_status( struct async *async ) { + assert( async->state == ASYNC_INITIAL ); + async->state = ASYNC_UNKNOWN_STATUS; async->unknown_status = 1; async->direct_result = 0; } @@ -510,6 +636,8 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota
if (async_alerted( async ) && status == STATUS_PENDING) /* restart it */ { + assert( async->state == ASYNC_INITIAL || async->state == ASYNC_ALERTED ); + async->state = ASYNC_IN_PROGRESS; async->terminated = 0; async->alerted = 0; async_reselect( async ); @@ -547,6 +675,7 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota else if (async->fd) set_fd_signaled( async->fd, 1 ); }
+ async->state = ASYNC_COMPLETED; if (!async->signaled) { async->signaled = 1;