mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2024-11-21 17:09:06 -07:00
Merge branch 'async-proposal-00' into 'master'
Draft: Refactor the async state flags See merge request wine/wine!6369
This commit is contained in:
commit
90bedd8305
1 changed files with 154 additions and 58 deletions
212
server/async.c
212
server/async.c
|
@ -34,6 +34,48 @@
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
|
|
||||||
|
enum async_state
|
||||||
|
{
|
||||||
|
/* The I/O operation has just initiated, or initial status is known. */
|
||||||
|
ASYNC_INITIAL,
|
||||||
|
|
||||||
|
/* The I/O operation has just initiated via create_request_async(). */
|
||||||
|
ASYNC_INITIAL_DIRECT_RESULT,
|
||||||
|
|
||||||
|
/* 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 (APC result) but not been
|
||||||
|
* acknowledged by the client.
|
||||||
|
*
|
||||||
|
* The completion is being delivered to the client indirectly via
|
||||||
|
* APC_ASYNC_IO. The client had no chance to fill the IOSB synchronously,
|
||||||
|
* due to unknwon initial status (e.g., processed by winedevice.exe).
|
||||||
|
*/
|
||||||
|
ASYNC_FINALIZING_SYNC_APC_RESULT,
|
||||||
|
|
||||||
|
/* The I/O operation has finished synchronously (direct result) but not
|
||||||
|
* been acknowledged by the client.
|
||||||
|
*
|
||||||
|
* The completion is being delivered to the client directly via server
|
||||||
|
* request return. The client may proceed to fill the IOSB synchronously,
|
||||||
|
* and notify the server that it has done so.
|
||||||
|
*/
|
||||||
|
ASYNC_FINALIZING_SYNC_DIRECT_RESULT,
|
||||||
|
|
||||||
|
/* 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 async
|
||||||
{
|
{
|
||||||
struct object obj; /* object header */
|
struct object obj; /* object header */
|
||||||
|
@ -49,13 +91,9 @@ struct async
|
||||||
struct iosb *iosb; /* I/O status block */
|
struct iosb *iosb; /* I/O status block */
|
||||||
obj_handle_t wait_handle; /* pre-allocated wait handle */
|
obj_handle_t wait_handle; /* pre-allocated wait handle */
|
||||||
unsigned int initial_status; /* status returned from initial request */
|
unsigned int initial_status; /* status returned from initial request */
|
||||||
unsigned int signaled :1;
|
enum async_state state;
|
||||||
unsigned int pending :1; /* request successfully queued, but pending */
|
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 */
|
|
||||||
unsigned int alerted :1; /* fd is signaled, but we are waiting for client-side I/O */
|
|
||||||
unsigned int terminated :1; /* async has been terminated */
|
|
||||||
unsigned int canceled :1; /* have we already queued cancellation for this async? */
|
unsigned int canceled :1; /* have we already queued cancellation for this async? */
|
||||||
unsigned int unknown_status :1; /* initial status is not known yet */
|
|
||||||
unsigned int blocking :1; /* async is blocking */
|
unsigned int blocking :1; /* async is blocking */
|
||||||
unsigned int is_system :1; /* background system operation not affecting userspace visible state. */
|
unsigned int is_system :1; /* background system operation not affecting userspace visible state. */
|
||||||
struct completion *completion; /* completion associated with fd */
|
struct completion *completion; /* completion associated with fd */
|
||||||
|
@ -110,7 +148,28 @@ static int async_signaled( struct object *obj, struct wait_queue_entry *entry )
|
||||||
{
|
{
|
||||||
struct async *async = (struct async *)obj;
|
struct async *async = (struct async *)obj;
|
||||||
assert( obj->ops == &async_ops );
|
assert( obj->ops == &async_ops );
|
||||||
return async->signaled;
|
switch (async->state)
|
||||||
|
{
|
||||||
|
case ASYNC_INITIAL:
|
||||||
|
case ASYNC_INITIAL_DIRECT_RESULT:
|
||||||
|
case ASYNC_UNKNOWN_STATUS:
|
||||||
|
case ASYNC_FINALIZING_SYNC_APC_RESULT:
|
||||||
|
return 0;
|
||||||
|
case ASYNC_FINALIZING_SYNC_DIRECT_RESULT:
|
||||||
|
/* The client will "wait" on the async to signal completion. */
|
||||||
|
return 1;
|
||||||
|
case ASYNC_IN_PROGRESS:
|
||||||
|
case ASYNC_ALERTED:
|
||||||
|
case ASYNC_FINALIZING_ASYNC:
|
||||||
|
/* If nonblocking, the client will "wait" on the async to close it. */
|
||||||
|
return !async->blocking;
|
||||||
|
case ASYNC_COMPLETED:
|
||||||
|
/* If there is an open async handle, notify the waiter of completion. */
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
assert( 0 );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void async_satisfied( struct object *obj, struct wait_queue_entry *entry )
|
static void async_satisfied( struct object *obj, struct wait_queue_entry *entry )
|
||||||
|
@ -121,10 +180,9 @@ static void async_satisfied( struct object *obj, struct wait_queue_entry *entry
|
||||||
/* we only return an async handle for asyncs created via create_request_async() */
|
/* we only return an async handle for asyncs created via create_request_async() */
|
||||||
assert( async->iosb );
|
assert( async->iosb );
|
||||||
|
|
||||||
if (async->direct_result)
|
if (async->state == ASYNC_FINALIZING_SYNC_DIRECT_RESULT)
|
||||||
{
|
{
|
||||||
async_set_result( &async->obj, async->iosb->status, async->iosb->result );
|
async_set_result( &async->obj, async->iosb->status, async->iosb->result );
|
||||||
async->direct_result = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (async->initial_status == STATUS_PENDING && async->blocking)
|
if (async->initial_status == STATUS_PENDING && async->blocking)
|
||||||
|
@ -161,24 +219,70 @@ static void async_destroy( struct object *obj )
|
||||||
release_object( async->thread );
|
release_object( async->thread );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int async_terminated( const struct async *async )
|
||||||
|
{
|
||||||
|
switch (async->state)
|
||||||
|
{
|
||||||
|
case ASYNC_INITIAL:
|
||||||
|
case ASYNC_INITIAL_DIRECT_RESULT:
|
||||||
|
case ASYNC_IN_PROGRESS:
|
||||||
|
return 0;
|
||||||
|
case ASYNC_UNKNOWN_STATUS:
|
||||||
|
case ASYNC_ALERTED:
|
||||||
|
case ASYNC_FINALIZING_SYNC_APC_RESULT:
|
||||||
|
case ASYNC_FINALIZING_SYNC_DIRECT_RESULT:
|
||||||
|
case ASYNC_FINALIZING_ASYNC:
|
||||||
|
case ASYNC_COMPLETED:
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
assert( 0 );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* notifies client thread of new status of its async request */
|
/* notifies client thread of new status of its async request */
|
||||||
void async_terminate( struct async *async, unsigned int status )
|
void async_terminate( struct async *async, unsigned int status )
|
||||||
{
|
{
|
||||||
struct iosb *iosb = async->iosb;
|
struct iosb *iosb = async->iosb;
|
||||||
|
|
||||||
if (async->terminated) return;
|
if (async_terminated( async )) return;
|
||||||
|
assert( async->state == ASYNC_INITIAL || async->state == ASYNC_INITIAL_DIRECT_RESULT || async->state == ASYNC_IN_PROGRESS );
|
||||||
|
|
||||||
async->terminated = 1;
|
|
||||||
if (async->iosb && async->iosb->status == STATUS_PENDING) async->iosb->status = status;
|
|
||||||
if (status == STATUS_ALERTED)
|
if (status == STATUS_ALERTED)
|
||||||
async->alerted = 1;
|
{
|
||||||
|
if (async->state == ASYNC_INITIAL_DIRECT_RESULT)
|
||||||
|
{
|
||||||
|
async->state = ASYNC_UNKNOWN_STATUS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
async->state = ASYNC_ALERTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (async->state == ASYNC_INITIAL)
|
||||||
|
async->state = ASYNC_FINALIZING_SYNC_APC_RESULT;
|
||||||
|
else if (async->state == ASYNC_INITIAL_DIRECT_RESULT)
|
||||||
|
async->state = ASYNC_FINALIZING_SYNC_DIRECT_RESULT;
|
||||||
|
else
|
||||||
|
async->state = ASYNC_FINALIZING_ASYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (async->iosb && async->iosb->status == STATUS_PENDING) async->iosb->status = status;
|
||||||
|
|
||||||
|
if (async->state == ASYNC_FINALIZING_SYNC_DIRECT_RESULT ||
|
||||||
|
(async->state == ASYNC_ALERTED || async->state == ASYNC_FINALIZING_ASYNC) && !async->blocking)
|
||||||
|
{
|
||||||
|
wake_up( &async->obj, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
/* if no APC could be queued (e.g. the process is terminated),
|
/* if no APC could be queued (e.g. the process is terminated),
|
||||||
* thread_queue_apc() may trigger async_set_result(), which may drop the
|
* thread_queue_apc() may trigger async_set_result(), which may drop the
|
||||||
* last reference to the async, so grab a temporary reference here */
|
* last reference to the async, so grab a temporary reference here */
|
||||||
grab_object( async );
|
grab_object( async );
|
||||||
|
|
||||||
if (!async->direct_result)
|
if (async->state != ASYNC_FINALIZING_SYNC_DIRECT_RESULT && async->state != ASYNC_UNKNOWN_STATUS)
|
||||||
{
|
{
|
||||||
union apc_call data;
|
union apc_call data;
|
||||||
|
|
||||||
|
@ -269,14 +373,10 @@ struct async *create_async( struct fd *fd, struct thread *thread, const struct a
|
||||||
async->queue = NULL;
|
async->queue = NULL;
|
||||||
async->fd = (struct fd *)grab_object( fd );
|
async->fd = (struct fd *)grab_object( fd );
|
||||||
async->initial_status = STATUS_PENDING;
|
async->initial_status = STATUS_PENDING;
|
||||||
async->signaled = 0;
|
async->state = ASYNC_INITIAL;
|
||||||
async->pending = 1;
|
async->pending = 1;
|
||||||
async->wait_handle = 0;
|
async->wait_handle = 0;
|
||||||
async->direct_result = 0;
|
|
||||||
async->alerted = 0;
|
|
||||||
async->terminated = 0;
|
|
||||||
async->canceled = 0;
|
async->canceled = 0;
|
||||||
async->unknown_status = 0;
|
|
||||||
async->blocking = !is_fd_overlapped( fd );
|
async->blocking = !is_fd_overlapped( fd );
|
||||||
async->is_system = 0;
|
async->is_system = 0;
|
||||||
async->completion = fd_get_completion( fd, &async->comp_key );
|
async->completion = fd_get_completion( fd, &async->comp_key );
|
||||||
|
@ -305,21 +405,22 @@ struct async *create_async( struct fd *fd, struct thread *thread, const struct a
|
||||||
void async_set_initial_status( struct async *async, unsigned int status )
|
void async_set_initial_status( struct async *async, unsigned int status )
|
||||||
{
|
{
|
||||||
async->initial_status = 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 )
|
void set_async_pending( struct async *async )
|
||||||
{
|
{
|
||||||
if (!async->terminated)
|
if (async->state == ASYNC_INITIAL_DIRECT_RESULT || async->state == ASYNC_UNKNOWN_STATUS)
|
||||||
async->pending = 1;
|
async->pending = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void async_wake_obj( struct async *async )
|
void async_wake_obj( struct async *async )
|
||||||
{
|
{
|
||||||
assert( !async->unknown_status );
|
assert( async->state == ASYNC_INITIAL );
|
||||||
|
async->state = ASYNC_IN_PROGRESS;
|
||||||
if (!async->blocking)
|
if (!async->blocking)
|
||||||
{
|
{
|
||||||
async->signaled = 1;
|
|
||||||
wake_up( &async->obj, 0 );
|
wake_up( &async->obj, 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -336,7 +437,7 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_
|
||||||
{
|
{
|
||||||
async->blocking = force_blocking || async->blocking;
|
async->blocking = force_blocking || async->blocking;
|
||||||
|
|
||||||
if (async->unknown_status)
|
if (async->state == ASYNC_UNKNOWN_STATUS)
|
||||||
{
|
{
|
||||||
/* even the initial status is not known yet */
|
/* even the initial status is not known yet */
|
||||||
set_error( STATUS_PENDING );
|
set_error( STATUS_PENDING );
|
||||||
|
@ -353,17 +454,16 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_
|
||||||
* instead.
|
* instead.
|
||||||
*
|
*
|
||||||
* since we're deferring the initial I/O (to the client), we mark the
|
* since we're deferring the initial I/O (to the client), we mark the
|
||||||
* async as having unknown initial status (unknown_status = 1). note
|
* async as having unknown initial status. note that we don't reuse
|
||||||
* that we don't reuse async_set_unknown_status() here. this is because
|
* async_set_unknown_status() here. this is because the one
|
||||||
* the one responsible for performing the I/O is not the device driver,
|
* responsible for performing the I/O is not the device driver, but
|
||||||
* but instead the client that requested the I/O in the first place.
|
* instead the client that requested the I/O in the first place.
|
||||||
*
|
*
|
||||||
* also, async_set_unknown_status() would set direct_result to zero
|
* also, async_set_unknown_status() would eventually force APC_ASYNC_IO
|
||||||
* forcing APC_ASYNC_IO to fire in async_terminate(), which is not
|
* to fire in async_terminate(), which is not useful due to subtle
|
||||||
* useful due to subtle semantic differences between synchronous and
|
* semantic differences between synchronous and asynchronous
|
||||||
* asynchronous completion.
|
* completion.
|
||||||
*/
|
*/
|
||||||
async->unknown_status = 1;
|
|
||||||
async_terminate( async, STATUS_ALERTED );
|
async_terminate( async, STATUS_ALERTED );
|
||||||
return async->wait_handle;
|
return async->wait_handle;
|
||||||
}
|
}
|
||||||
|
@ -398,11 +498,11 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_
|
||||||
if (async->iosb->status != STATUS_PENDING)
|
if (async->iosb->status != STATUS_PENDING)
|
||||||
{
|
{
|
||||||
if (result) *result = async->iosb->result;
|
if (result) *result = async->iosb->result;
|
||||||
async->signaled = 1;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
async->direct_result = 0;
|
assert( async->state == ASYNC_INITIAL_DIRECT_RESULT );
|
||||||
|
async->state = ASYNC_IN_PROGRESS;
|
||||||
async->pending = 1;
|
async->pending = 1;
|
||||||
if (!async->blocking)
|
if (!async->blocking)
|
||||||
{
|
{
|
||||||
|
@ -457,8 +557,8 @@ void async_request_complete_alloc( struct async *async, unsigned int status, dat
|
||||||
/* mark an async as having unknown initial status */
|
/* mark an async as having unknown initial status */
|
||||||
void async_set_unknown_status( struct async *async )
|
void async_set_unknown_status( struct async *async )
|
||||||
{
|
{
|
||||||
async->unknown_status = 1;
|
assert( async->state == ASYNC_INITIAL_DIRECT_RESULT );
|
||||||
async->direct_result = 0;
|
async->state = ASYNC_UNKNOWN_STATUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set the timeout of an async operation */
|
/* set the timeout of an async operation */
|
||||||
|
@ -491,21 +591,21 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota
|
||||||
|
|
||||||
if (obj->ops != &async_ops) return; /* in case the client messed up the APC results */
|
if (obj->ops != &async_ops) return; /* in case the client messed up the APC results */
|
||||||
|
|
||||||
assert( async->terminated ); /* it must have been woken up if we get a result */
|
assert( async_terminated( async ) ); /* it must have been woken up if we get a result */
|
||||||
|
|
||||||
if (async->unknown_status) async_set_initial_status( async, status );
|
if (async->state == ASYNC_UNKNOWN_STATUS) async_set_initial_status( async, status );
|
||||||
|
assert( async->state != ASYNC_UNKNOWN_STATUS );
|
||||||
|
|
||||||
if (async->alerted && status == STATUS_PENDING) /* restart it */
|
if ((async->state == ASYNC_INITIAL || async->state == ASYNC_ALERTED) &&
|
||||||
|
status == STATUS_PENDING) /* restart it */
|
||||||
{
|
{
|
||||||
async->terminated = 0;
|
async->state = ASYNC_IN_PROGRESS;
|
||||||
async->alerted = 0;
|
|
||||||
async_reselect( async );
|
async_reselect( async );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (async->timeout) remove_timeout_user( async->timeout );
|
if (async->timeout) remove_timeout_user( async->timeout );
|
||||||
async->timeout = NULL;
|
async->timeout = NULL;
|
||||||
async->terminated = 1;
|
|
||||||
if (async->iosb) async->iosb->status = status;
|
if (async->iosb) async->iosb->status = status;
|
||||||
|
|
||||||
/* don't signal completion if the async failed synchronously
|
/* don't signal completion if the async failed synchronously
|
||||||
|
@ -534,11 +634,8 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota
|
||||||
else if (async->fd && !async->is_system) set_fd_signaled( async->fd, 1 );
|
else if (async->fd && !async->is_system) set_fd_signaled( async->fd, 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!async->signaled)
|
async->state = ASYNC_COMPLETED;
|
||||||
{
|
wake_up( &async->obj, 0 );
|
||||||
async->signaled = 1;
|
|
||||||
wake_up( &async->obj, 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
async_call_completion_callback( async );
|
async_call_completion_callback( async );
|
||||||
|
|
||||||
|
@ -558,7 +655,7 @@ int async_queue_has_waiting_asyncs( struct async_queue *queue )
|
||||||
struct async *async;
|
struct async *async;
|
||||||
|
|
||||||
LIST_FOR_EACH_ENTRY( async, &queue->queue, struct async, queue_entry )
|
LIST_FOR_EACH_ENTRY( async, &queue->queue, struct async, queue_entry )
|
||||||
if (!async->unknown_status) return 1;
|
if (async->state != ASYNC_UNKNOWN_STATUS) return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -571,7 +668,7 @@ int async_waiting( struct async_queue *queue )
|
||||||
|
|
||||||
if (!(ptr = list_head( &queue->queue ))) return 0;
|
if (!(ptr = list_head( &queue->queue ))) return 0;
|
||||||
async = LIST_ENTRY( ptr, struct async, queue_entry );
|
async = LIST_ENTRY( ptr, struct async, queue_entry );
|
||||||
return !async->terminated;
|
return !async_terminated( async );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cancel_async( struct process *process, struct object *obj, struct thread *thread, client_ptr_t iosb )
|
static int cancel_async( struct process *process, struct object *obj, struct thread *thread, client_ptr_t iosb )
|
||||||
|
@ -586,7 +683,7 @@ static int cancel_async( struct process *process, struct object *obj, struct thr
|
||||||
restart:
|
restart:
|
||||||
LIST_FOR_EACH_ENTRY( async, &process->asyncs, struct async, process_entry )
|
LIST_FOR_EACH_ENTRY( async, &process->asyncs, struct async, process_entry )
|
||||||
{
|
{
|
||||||
if (async->terminated || async->canceled || async->is_system) continue;
|
if (async_terminated( async ) || async->canceled || async->is_system) continue;
|
||||||
if ((!obj || (get_fd_user( async->fd ) == obj)) &&
|
if ((!obj || (get_fd_user( async->fd ) == obj)) &&
|
||||||
(!thread || async->thread == thread) &&
|
(!thread || async->thread == thread) &&
|
||||||
(!iosb || async->data.iosb == iosb))
|
(!iosb || async->data.iosb == iosb))
|
||||||
|
@ -608,7 +705,7 @@ static int cancel_blocking( struct process *process, struct thread *thread, clie
|
||||||
restart:
|
restart:
|
||||||
LIST_FOR_EACH_ENTRY( async, &process->asyncs, struct async, process_entry )
|
LIST_FOR_EACH_ENTRY( async, &process->asyncs, struct async, process_entry )
|
||||||
{
|
{
|
||||||
if (async->terminated || async->canceled) continue;
|
if (async_terminated( async ) || async->canceled) continue;
|
||||||
if (async->blocking && async->thread == thread &&
|
if (async->blocking && async->thread == thread &&
|
||||||
(!iosb || async->data.iosb == iosb))
|
(!iosb || async->data.iosb == iosb))
|
||||||
{
|
{
|
||||||
|
@ -628,7 +725,7 @@ void cancel_process_asyncs( struct process *process )
|
||||||
restart:
|
restart:
|
||||||
LIST_FOR_EACH_ENTRY( async, &process->asyncs, struct async, process_entry )
|
LIST_FOR_EACH_ENTRY( async, &process->asyncs, struct async, process_entry )
|
||||||
{
|
{
|
||||||
if (async->terminated || async->canceled) continue;
|
if (async_terminated( async ) || async->canceled) continue;
|
||||||
async->canceled = 1;
|
async->canceled = 1;
|
||||||
fd_cancel_async( async->fd, async );
|
fd_cancel_async( async->fd, async );
|
||||||
goto restart;
|
goto restart;
|
||||||
|
@ -647,7 +744,7 @@ int async_close_obj_handle( struct object *obj, struct process *process, obj_han
|
||||||
restart:
|
restart:
|
||||||
LIST_FOR_EACH_ENTRY( async, &process->asyncs, struct async, process_entry )
|
LIST_FOR_EACH_ENTRY( async, &process->asyncs, struct async, process_entry )
|
||||||
{
|
{
|
||||||
if (async->terminated || async->canceled || get_fd_user( async->fd ) != obj) continue;
|
if (async_terminated( async ) || async->canceled || get_fd_user( async->fd ) != obj) continue;
|
||||||
if (!async->completion || !async->data.apc_context || async->event) continue;
|
if (!async->completion || !async->data.apc_context || async->event) continue;
|
||||||
|
|
||||||
async->canceled = 1;
|
async->canceled = 1;
|
||||||
|
@ -664,7 +761,7 @@ void cancel_terminating_thread_asyncs( struct thread *thread )
|
||||||
restart:
|
restart:
|
||||||
LIST_FOR_EACH_ENTRY( async, &thread->process->asyncs, struct async, process_entry )
|
LIST_FOR_EACH_ENTRY( async, &thread->process->asyncs, struct async, process_entry )
|
||||||
{
|
{
|
||||||
if (async->thread != thread || async->terminated || async->canceled) continue;
|
if (async->thread != thread || async_terminated( async ) || async->canceled) continue;
|
||||||
if (async->completion && async->data.apc_context && !async->event) continue;
|
if (async->completion && async->data.apc_context && !async->event) continue;
|
||||||
if (async->is_system) continue;
|
if (async->is_system) continue;
|
||||||
|
|
||||||
|
@ -771,7 +868,7 @@ struct async *create_request_async( struct fd *fd, unsigned int comp_flags, cons
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
async->pending = 0;
|
async->pending = 0;
|
||||||
async->direct_result = 1;
|
async->state = ASYNC_INITIAL_DIRECT_RESULT;
|
||||||
async->is_system = !!is_system;
|
async->is_system = !!is_system;
|
||||||
async->comp_flags = comp_flags;
|
async->comp_flags = comp_flags;
|
||||||
}
|
}
|
||||||
|
@ -793,7 +890,7 @@ struct async *find_pending_async( struct async_queue *queue )
|
||||||
{
|
{
|
||||||
struct async *async;
|
struct async *async;
|
||||||
LIST_FOR_EACH_ENTRY( async, &queue->queue, struct async, queue_entry )
|
LIST_FOR_EACH_ENTRY( async, &queue->queue, struct async, queue_entry )
|
||||||
if (!async->terminated) return (struct async *)grab_object( async );
|
if (!async_terminated( async )) return (struct async *)grab_object( async );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -863,7 +960,7 @@ DECL_HANDLER(set_async_direct_result)
|
||||||
|
|
||||||
if (!async) return;
|
if (!async) return;
|
||||||
|
|
||||||
if (!async->unknown_status || !async->terminated || !async->alerted)
|
if (async->state != ASYNC_UNKNOWN_STATUS)
|
||||||
{
|
{
|
||||||
set_error( STATUS_INVALID_PARAMETER );
|
set_error( STATUS_INVALID_PARAMETER );
|
||||||
release_object( &async->obj );
|
release_object( &async->obj );
|
||||||
|
@ -872,7 +969,6 @@ DECL_HANDLER(set_async_direct_result)
|
||||||
|
|
||||||
if (status == STATUS_PENDING)
|
if (status == STATUS_PENDING)
|
||||||
{
|
{
|
||||||
async->direct_result = 0;
|
|
||||||
async->pending = 1;
|
async->pending = 1;
|
||||||
}
|
}
|
||||||
else if (req->mark_pending)
|
else if (req->mark_pending)
|
||||||
|
|
Loading…
Reference in a new issue