diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 852bfde6f7b..5857c46b159 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -659,6 +659,8 @@ static int wait_reply( void *cookie ) */ static void call_apcs( BOOL alertable ) { + NTSTATUS ret; + HANDLE handle = 0; FARPROC proc; LARGE_INTEGER time; void *arg1, *arg2, *arg3; @@ -669,18 +671,23 @@ static void call_apcs( BOOL alertable ) SERVER_START_REQ( get_apc ) { req->alertable = alertable; - if (!wine_server_call( req )) type = reply->type; - proc = reply->func; - arg1 = reply->arg1; - arg2 = reply->arg2; - arg3 = reply->arg3; + req->prev = handle; + if (!(ret = wine_server_call( req ))) + { + handle = reply->handle; + type = reply->type; + proc = reply->func; + arg1 = reply->arg1; + arg2 = reply->arg2; + arg3 = reply->arg3; + } } SERVER_END_REQ; + if (ret) return; /* no more APCs */ + switch (type) { - case APC_NONE: - return; /* no more APCs */ case APC_USER: proc( arg1, arg2, arg3 ); break; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 040afcf115d..68589859b57 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -529,10 +529,12 @@ struct get_apc_request { struct request_header __header; int alertable; + obj_handle_t prev; }; struct get_apc_reply { struct reply_header __header; + obj_handle_t handle; void* func; int type; void* arg1; @@ -4415,6 +4417,6 @@ union generic_reply struct query_symlink_reply query_symlink_reply; }; -#define SERVER_PROTOCOL_VERSION 261 +#define SERVER_PROTOCOL_VERSION 262 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index 80821abb899..7cde3122f0d 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -447,7 +447,9 @@ struct token_groups /* Get next APC to call */ @REQ(get_apc) int alertable; /* is thread alertable? */ + obj_handle_t prev; /* handle to previous APC */ @REPLY + obj_handle_t handle; /* handle to APC */ void* func; /* function to call */ int type; /* function type */ void* arg1; /* function arguments */ diff --git a/server/thread.c b/server/thread.c index 2d05ffae4e9..630447a6e7d 100644 --- a/server/thread.c +++ b/server/thread.c @@ -71,6 +71,7 @@ struct thread_apc struct object obj; /* object header */ struct list entry; /* queue linked list */ struct object *owner; /* object that queued this apc */ + int executed; /* has it been executed by the client? */ void *func; /* function to call in client */ enum apc_type type; /* type of apc function */ void *arg1; /* function arguments */ @@ -310,7 +311,8 @@ static void dump_thread_apc( struct object *obj, int verbose ) static int thread_apc_signaled( struct object *obj, struct thread *thread ) { - return 0; + struct thread_apc *apc = (struct thread_apc *)obj; + return apc->executed; } /* get a thread pointer from a thread id (and increment the refcount) */ @@ -679,6 +681,7 @@ int thread_queue_apc( struct thread *thread, struct object *owner, void *func, apc->arg1 = arg1; apc->arg2 = arg2; apc->arg3 = arg3; + apc->executed = 0; list_add_tail( queue, &apc->entry ); if (!list_prev( queue, &apc->entry )) /* first one */ wake_thread( thread ); @@ -1061,13 +1064,22 @@ DECL_HANDLER(get_apc) { struct thread_apc *apc; + if (req->prev) + { + if (!(apc = (struct thread_apc *)get_handle_obj( current->process, req->prev, + 0, &thread_apc_ops ))) return; + apc->executed = 1; + wake_up( &apc->obj, 0 ); + close_handle( current->process, req->prev ); + release_object( apc ); + } + for (;;) { if (!(apc = thread_dequeue_apc( current, !req->alertable ))) { /* no more APCs */ - reply->func = NULL; - reply->type = APC_NONE; + set_error( STATUS_PENDING ); return; } /* Optimization: ignore APCs that have a NULL func; they are only used @@ -1077,11 +1089,15 @@ DECL_HANDLER(get_apc) if (apc->func || apc->type == APC_ASYNC_IO) break; release_object( apc ); } - reply->func = apc->func; - reply->type = apc->type; - reply->arg1 = apc->arg1; - reply->arg2 = apc->arg2; - reply->arg3 = apc->arg3; + + if ((reply->handle = alloc_handle( current->process, apc, SYNCHRONIZE, 0 ))) + { + reply->func = apc->func; + reply->type = apc->type; + reply->arg1 = apc->arg1; + reply->arg2 = apc->arg2; + reply->arg3 = apc->arg3; + } release_object( apc ); } diff --git a/server/trace.c b/server/trace.c index b128ad52e27..50184231d40 100644 --- a/server/trace.c +++ b/server/trace.c @@ -854,11 +854,13 @@ static void dump_queue_apc_request( const struct queue_apc_request *req ) static void dump_get_apc_request( const struct get_apc_request *req ) { - fprintf( stderr, " alertable=%d", req->alertable ); + fprintf( stderr, " alertable=%d,", req->alertable ); + fprintf( stderr, " prev=%p", req->prev ); } static void dump_get_apc_reply( const struct get_apc_reply *req ) { + fprintf( stderr, " handle=%p,", req->handle ); fprintf( stderr, " func=%p,", req->func ); fprintf( stderr, " type=%d,", req->type ); fprintf( stderr, " arg1=%p,", req->arg1 );