server: Add a generic apc_call structure to make it easier to extend, and more type-safe.
This commit is contained in:
parent
49b49c30fc
commit
5c8421d3e7
|
@ -660,14 +660,11 @@ static int wait_reply( void *cookie )
|
|||
static void call_apcs( BOOL alertable )
|
||||
{
|
||||
NTSTATUS ret;
|
||||
apc_call_t call;
|
||||
HANDLE handle = 0;
|
||||
FARPROC proc;
|
||||
LARGE_INTEGER time;
|
||||
void *arg1, *arg2, *arg3;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int type = APC_NONE;
|
||||
SERVER_START_REQ( get_apc )
|
||||
{
|
||||
req->alertable = alertable;
|
||||
|
@ -675,34 +672,33 @@ static void call_apcs( BOOL alertable )
|
|||
if (!(ret = wine_server_call( req )))
|
||||
{
|
||||
handle = reply->handle;
|
||||
type = reply->type;
|
||||
proc = reply->func;
|
||||
arg1 = reply->arg1;
|
||||
arg2 = reply->arg2;
|
||||
arg3 = reply->arg3;
|
||||
call = reply->call;
|
||||
}
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (ret) return; /* no more APCs */
|
||||
|
||||
switch (type)
|
||||
switch (call.type)
|
||||
{
|
||||
case APC_USER:
|
||||
proc( arg1, arg2, arg3 );
|
||||
call.user.func( call.user.args[0], call.user.args[1], call.user.args[2] );
|
||||
break;
|
||||
case APC_TIMER:
|
||||
{
|
||||
LARGE_INTEGER time;
|
||||
/* convert sec/usec to NT time */
|
||||
RtlSecondsSince1970ToTime( (time_t)arg1, &time );
|
||||
time.QuadPart += (DWORD)arg2 * 10;
|
||||
proc( arg3, time.u.LowPart, time.u.HighPart );
|
||||
RtlSecondsSince1970ToTime( call.timer.time.sec, &time );
|
||||
time.QuadPart += call.timer.time.usec * 10;
|
||||
call.timer.func( call.timer.arg, time.u.LowPart, time.u.HighPart );
|
||||
break;
|
||||
}
|
||||
case APC_ASYNC_IO:
|
||||
NtCurrentTeb()->num_async_io--;
|
||||
proc( arg1, (IO_STATUS_BLOCK*)arg2, (ULONG)arg3 );
|
||||
call.async_io.func( call.async_io.user, call.async_io.sb, call.async_io.status );
|
||||
break;
|
||||
default:
|
||||
server_protocol_error( "get_apc_request: bad type %d\n", type );
|
||||
server_protocol_error( "get_apc_request: bad type %d\n", call.type );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -638,11 +638,15 @@ NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1
|
|||
SERVER_START_REQ( queue_apc )
|
||||
{
|
||||
req->handle = handle;
|
||||
req->user = 1;
|
||||
req->func = func;
|
||||
req->arg1 = (void *)arg1;
|
||||
req->arg2 = (void *)arg2;
|
||||
req->arg3 = (void *)arg3;
|
||||
if (func)
|
||||
{
|
||||
req->call.type = APC_USER;
|
||||
req->call.user.func = func;
|
||||
req->call.user.args[0] = arg1;
|
||||
req->call.user.args[1] = arg2;
|
||||
req->call.user.args[2] = arg3;
|
||||
}
|
||||
else req->call.type = APC_NONE; /* wake up only */
|
||||
ret = wine_server_call( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
|
|
@ -209,6 +209,34 @@ struct token_groups
|
|||
|
||||
};
|
||||
|
||||
enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC_IO };
|
||||
|
||||
typedef union
|
||||
{
|
||||
enum apc_type type;
|
||||
struct
|
||||
{
|
||||
enum apc_type type;
|
||||
void (__stdcall *func)(unsigned long,unsigned long,unsigned long);
|
||||
unsigned long args[3];
|
||||
} user;
|
||||
struct
|
||||
{
|
||||
enum apc_type type;
|
||||
void (__stdcall *func)(void*, unsigned int, unsigned int);
|
||||
abs_time_t time;
|
||||
void *arg;
|
||||
} timer;
|
||||
struct
|
||||
{
|
||||
enum apc_type type;
|
||||
void (__stdcall *func)(void*, void*, unsigned int);
|
||||
void *user;
|
||||
void *sb;
|
||||
unsigned int status;
|
||||
} async_io;
|
||||
} apc_call_t;
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -512,11 +540,7 @@ struct queue_apc_request
|
|||
{
|
||||
struct request_header __header;
|
||||
obj_handle_t handle;
|
||||
int user;
|
||||
void* func;
|
||||
void* arg1;
|
||||
void* arg2;
|
||||
void* arg3;
|
||||
apc_call_t call;
|
||||
};
|
||||
struct queue_apc_reply
|
||||
{
|
||||
|
@ -535,13 +559,8 @@ struct get_apc_reply
|
|||
{
|
||||
struct reply_header __header;
|
||||
obj_handle_t handle;
|
||||
void* func;
|
||||
int type;
|
||||
void* arg1;
|
||||
void* arg2;
|
||||
void* arg3;
|
||||
apc_call_t call;
|
||||
};
|
||||
enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC_IO };
|
||||
|
||||
|
||||
|
||||
|
@ -4417,6 +4436,6 @@ union generic_reply
|
|||
struct query_symlink_reply query_symlink_reply;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 262
|
||||
#define SERVER_PROTOCOL_VERSION 263
|
||||
|
||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||
|
|
11
server/fd.c
11
server/fd.c
|
@ -1283,8 +1283,15 @@ struct async
|
|||
/* destroys the server side of it */
|
||||
static void async_terminate( struct async *async, int status )
|
||||
{
|
||||
thread_queue_apc( async->thread, NULL, async->apc, APC_ASYNC_IO,
|
||||
1, async->user, async->sb, (void *)status );
|
||||
apc_call_t data;
|
||||
|
||||
memset( &data, 0, sizeof(data) );
|
||||
data.type = APC_ASYNC_IO;
|
||||
data.async_io.func = async->apc;
|
||||
data.async_io.user = async->user;
|
||||
data.async_io.sb = async->sb;
|
||||
data.async_io.status = status;
|
||||
thread_queue_apc( async->thread, NULL, &data );
|
||||
|
||||
if (async->timeout) remove_timeout_user( async->timeout );
|
||||
async->timeout = NULL;
|
||||
|
|
|
@ -857,9 +857,16 @@ DECL_HANDLER(wait_named_pipe)
|
|||
server = find_server( pipe, ps_wait_open );
|
||||
if (server)
|
||||
{
|
||||
apc_call_t data;
|
||||
|
||||
/* there's already a server waiting for a client to connect */
|
||||
thread_queue_apc( current, NULL, req->func, APC_ASYNC_IO,
|
||||
1, req->event, NULL, (void *)STATUS_SUCCESS );
|
||||
memset( &data, 0, sizeof(data) );
|
||||
data.type = APC_ASYNC_IO;
|
||||
data.async_io.func = req->func;
|
||||
data.async_io.user = req->event;
|
||||
data.async_io.sb = NULL;
|
||||
data.async_io.status = STATUS_SUCCESS;
|
||||
thread_queue_apc( current, NULL, &data );
|
||||
release_object( server );
|
||||
}
|
||||
else
|
||||
|
|
|
@ -225,6 +225,34 @@ struct token_groups
|
|||
/* VARARGS(sids,SID); */
|
||||
};
|
||||
|
||||
enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC_IO };
|
||||
|
||||
typedef union
|
||||
{
|
||||
enum apc_type type;
|
||||
struct
|
||||
{
|
||||
enum apc_type type; /* APC_USER */
|
||||
void (__stdcall *func)(unsigned long,unsigned long,unsigned long);
|
||||
unsigned long args[3]; /* arguments for user function */
|
||||
} user;
|
||||
struct
|
||||
{
|
||||
enum apc_type type; /* APC_TIMER */
|
||||
void (__stdcall *func)(void*, unsigned int, unsigned int);
|
||||
abs_time_t time; /* absolute time of expiration */
|
||||
void *arg; /* user argument */
|
||||
} timer;
|
||||
struct
|
||||
{
|
||||
enum apc_type type; /* APC_ASYNC_IO */
|
||||
void (__stdcall *func)(void*, void*, unsigned int);
|
||||
void *user; /* user pointer */
|
||||
void *sb; /* status block */
|
||||
unsigned int status; /* I/O status */
|
||||
} async_io;
|
||||
} apc_call_t;
|
||||
|
||||
/****************************************************************/
|
||||
/* Request declarations */
|
||||
|
||||
|
@ -436,11 +464,7 @@ struct token_groups
|
|||
/* Queue an APC for a thread */
|
||||
@REQ(queue_apc)
|
||||
obj_handle_t handle; /* thread handle */
|
||||
int user; /* user or system apc? */
|
||||
void* func; /* function to call */
|
||||
void* arg1; /* params for function to call */
|
||||
void* arg2;
|
||||
void* arg3;
|
||||
apc_call_t call; /* call arguments */
|
||||
@END
|
||||
|
||||
|
||||
|
@ -450,13 +474,8 @@ struct token_groups
|
|||
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 */
|
||||
void* arg2;
|
||||
void* arg3;
|
||||
apc_call_t call; /* call arguments */
|
||||
@END
|
||||
enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC_IO };
|
||||
|
||||
|
||||
/* Close a handle for the current process */
|
||||
|
|
|
@ -72,11 +72,7 @@ struct thread_apc
|
|||
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 */
|
||||
void *arg2;
|
||||
void *arg3;
|
||||
apc_call_t call;
|
||||
};
|
||||
|
||||
static void dump_thread_apc( struct object *obj, int verbose );
|
||||
|
@ -306,7 +302,7 @@ static void dump_thread_apc( struct object *obj, int verbose )
|
|||
struct thread_apc *apc = (struct thread_apc *)obj;
|
||||
assert( obj->ops == &thread_apc_ops );
|
||||
|
||||
fprintf( stderr, "APC owner=%p type=%u\n", apc->owner, apc->type );
|
||||
fprintf( stderr, "APC owner=%p type=%u\n", apc->owner, apc->call.type );
|
||||
}
|
||||
|
||||
static int thread_apc_signaled( struct object *obj, struct thread *thread )
|
||||
|
@ -663,24 +659,33 @@ void wake_up( struct object *obj, int max )
|
|||
}
|
||||
}
|
||||
|
||||
/* return the apc queue to use for a given apc type */
|
||||
static inline struct list *get_apc_queue( struct thread *thread, enum apc_type type )
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case APC_NONE:
|
||||
case APC_USER:
|
||||
case APC_TIMER:
|
||||
return &thread->user_apc;
|
||||
default:
|
||||
return &thread->system_apc;
|
||||
}
|
||||
}
|
||||
|
||||
/* queue an async procedure call */
|
||||
int thread_queue_apc( struct thread *thread, struct object *owner, void *func,
|
||||
enum apc_type type, int system, void *arg1, void *arg2, void *arg3 )
|
||||
int thread_queue_apc( struct thread *thread, struct object *owner, const apc_call_t *call_data )
|
||||
{
|
||||
struct thread_apc *apc;
|
||||
struct list *queue = system ? &thread->system_apc : &thread->user_apc;
|
||||
struct list *queue = get_apc_queue( thread, call_data->type );
|
||||
|
||||
/* cancel a possible previous APC with the same owner */
|
||||
if (owner) thread_cancel_apc( thread, owner, system );
|
||||
if (owner) thread_cancel_apc( thread, owner, call_data->type );
|
||||
if (thread->state == TERMINATED) return 0;
|
||||
|
||||
if (!(apc = alloc_object( &thread_apc_ops ))) return 0;
|
||||
apc->owner = owner;
|
||||
apc->func = func;
|
||||
apc->type = type;
|
||||
apc->arg1 = arg1;
|
||||
apc->arg2 = arg2;
|
||||
apc->arg3 = arg3;
|
||||
apc->call = *call_data;
|
||||
apc->owner = owner;
|
||||
apc->executed = 0;
|
||||
list_add_tail( queue, &apc->entry );
|
||||
if (!list_prev( queue, &apc->entry )) /* first one */
|
||||
|
@ -690,10 +695,11 @@ int thread_queue_apc( struct thread *thread, struct object *owner, void *func,
|
|||
}
|
||||
|
||||
/* cancel the async procedure call owned by a specific object */
|
||||
void thread_cancel_apc( struct thread *thread, struct object *owner, int system )
|
||||
void thread_cancel_apc( struct thread *thread, struct object *owner, enum apc_type type )
|
||||
{
|
||||
struct thread_apc *apc;
|
||||
struct list *queue = system ? &thread->system_apc : &thread->user_apc;
|
||||
struct list *queue = get_apc_queue( thread, type );
|
||||
|
||||
LIST_FOR_EACH_ENTRY( apc, queue, struct thread_apc, entry )
|
||||
{
|
||||
if (apc->owner != owner) continue;
|
||||
|
@ -1053,8 +1059,16 @@ DECL_HANDLER(queue_apc)
|
|||
struct thread *thread;
|
||||
if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
|
||||
{
|
||||
thread_queue_apc( thread, NULL, req->func, APC_USER, !req->user,
|
||||
req->arg1, req->arg2, req->arg3 );
|
||||
switch( req->call.type )
|
||||
{
|
||||
case APC_NONE:
|
||||
case APC_USER:
|
||||
thread_queue_apc( thread, NULL, &req->call );
|
||||
break;
|
||||
default:
|
||||
set_error( STATUS_INVALID_PARAMETER );
|
||||
break;
|
||||
}
|
||||
release_object( thread );
|
||||
}
|
||||
}
|
||||
|
@ -1082,22 +1096,15 @@ DECL_HANDLER(get_apc)
|
|||
set_error( STATUS_PENDING );
|
||||
return;
|
||||
}
|
||||
/* Optimization: ignore APCs that have a NULL func; they are only used
|
||||
* to wake up a thread, but since we got here the thread woke up already.
|
||||
* Exception: for APC_ASYNC_IO, func == NULL is legal.
|
||||
/* Optimization: ignore APC_NONE calls, they are only used to
|
||||
* wake up a thread, but since we got here the thread woke up already.
|
||||
*/
|
||||
if (apc->func || apc->type == APC_ASYNC_IO) break;
|
||||
if (apc->call.type != APC_NONE) break;
|
||||
release_object( apc );
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
reply->call = apc->call;
|
||||
release_object( apc );
|
||||
}
|
||||
|
||||
|
|
|
@ -112,9 +112,8 @@ extern void remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
|||
extern void kill_thread( struct thread *thread, int violent_death );
|
||||
extern void break_thread( struct thread *thread );
|
||||
extern void wake_up( struct object *obj, int max );
|
||||
extern int thread_queue_apc( struct thread *thread, struct object *owner, void *func,
|
||||
enum apc_type type, int system, void *arg1, void *arg2, void *arg3 );
|
||||
extern void thread_cancel_apc( struct thread *thread, struct object *owner, int system );
|
||||
extern int thread_queue_apc( struct thread *thread, struct object *owner, const apc_call_t *call_data );
|
||||
extern void thread_cancel_apc( struct thread *thread, struct object *owner, enum apc_type type );
|
||||
extern int thread_add_inflight_fd( struct thread *thread, int client, int server );
|
||||
extern int thread_get_inflight_fd( struct thread *thread, int client );
|
||||
extern struct thread_snapshot *thread_snap( int *count );
|
||||
|
|
|
@ -104,8 +104,20 @@ static void timer_callback( void *private )
|
|||
/* queue an APC */
|
||||
if (timer->thread)
|
||||
{
|
||||
if (!thread_queue_apc( timer->thread, &timer->obj, timer->callback, APC_TIMER, 0,
|
||||
(void *)timer->when.tv_sec, (void *)timer->when.tv_usec, timer->arg))
|
||||
apc_call_t data;
|
||||
|
||||
memset( &data, 0, sizeof(data) );
|
||||
if (timer->callback)
|
||||
{
|
||||
data.type = APC_TIMER;
|
||||
data.timer.func = timer->callback;
|
||||
data.timer.time.sec = timer->when.tv_sec;
|
||||
data.timer.time.usec = timer->when.tv_usec;
|
||||
data.timer.arg = timer->arg;
|
||||
}
|
||||
else data.type = APC_NONE; /* wake up only */
|
||||
|
||||
if (!thread_queue_apc( timer->thread, &timer->obj, &data ))
|
||||
{
|
||||
release_object( timer->thread );
|
||||
timer->thread = NULL;
|
||||
|
@ -136,7 +148,7 @@ static int cancel_timer( struct timer *timer )
|
|||
}
|
||||
if (timer->thread)
|
||||
{
|
||||
thread_cancel_apc( timer->thread, &timer->obj, 0 );
|
||||
thread_cancel_apc( timer->thread, &timer->obj, APC_TIMER );
|
||||
release_object( timer->thread );
|
||||
timer->thread = NULL;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
static const void *cur_data;
|
||||
static data_size_t cur_size;
|
||||
|
||||
static const char *get_status_name( unsigned int status );
|
||||
|
||||
/* utility functions */
|
||||
|
||||
inline static void remove_data( data_size_t size )
|
||||
|
@ -96,6 +98,34 @@ static void dump_char_info( const char_info_t *info )
|
|||
fprintf( stderr, "',%04x}", info->attr );
|
||||
}
|
||||
|
||||
static void dump_apc_call( const apc_call_t *call )
|
||||
{
|
||||
fputc( '{', stderr );
|
||||
switch(call->type)
|
||||
{
|
||||
case APC_NONE:
|
||||
fprintf( stderr, "APC_NONE" );
|
||||
break;
|
||||
case APC_USER:
|
||||
fprintf( stderr, "APC_USER,args={%lx,%lx,%lx}",
|
||||
call->user.args[0], call->user.args[1], call->user.args[2] );
|
||||
break;
|
||||
case APC_TIMER:
|
||||
fprintf( stderr, "APC_TIMER,time=" );
|
||||
dump_abs_time( &call->timer.time );
|
||||
fprintf( stderr, ",arg=%p", call->timer.arg );
|
||||
break;
|
||||
case APC_ASYNC_IO:
|
||||
fprintf( stderr, "APC_ASYNC_IO,user=%p,sb=%p,status=%s",
|
||||
call->async_io.user, call->async_io.sb, get_status_name(call->async_io.status) );
|
||||
break;
|
||||
default:
|
||||
fprintf( stderr, "type=%u", call->type );
|
||||
break;
|
||||
}
|
||||
fputc( '}', stderr );
|
||||
}
|
||||
|
||||
static void dump_context( const CONTEXT *context )
|
||||
{
|
||||
#ifdef __i386__
|
||||
|
@ -845,11 +875,8 @@ static void dump_unload_dll_request( const struct unload_dll_request *req )
|
|||
static void dump_queue_apc_request( const struct queue_apc_request *req )
|
||||
{
|
||||
fprintf( stderr, " handle=%p,", req->handle );
|
||||
fprintf( stderr, " user=%d,", req->user );
|
||||
fprintf( stderr, " func=%p,", req->func );
|
||||
fprintf( stderr, " arg1=%p,", req->arg1 );
|
||||
fprintf( stderr, " arg2=%p,", req->arg2 );
|
||||
fprintf( stderr, " arg3=%p", req->arg3 );
|
||||
fprintf( stderr, " call=" );
|
||||
dump_apc_call( &req->call );
|
||||
}
|
||||
|
||||
static void dump_get_apc_request( const struct get_apc_request *req )
|
||||
|
@ -861,11 +888,8 @@ static void dump_get_apc_request( const struct get_apc_request *req )
|
|||
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 );
|
||||
fprintf( stderr, " arg2=%p,", req->arg2 );
|
||||
fprintf( stderr, " arg3=%p", req->arg3 );
|
||||
fprintf( stderr, " call=" );
|
||||
dump_apc_call( &req->call );
|
||||
}
|
||||
|
||||
static void dump_close_handle_request( const struct close_handle_request *req )
|
||||
|
|
|
@ -42,6 +42,7 @@ my %formats =
|
|||
"abs_time_t" => "&dump_abs_time",
|
||||
"rectangle_t" => "&dump_rectangle",
|
||||
"char_info_t" => "&dump_char_info",
|
||||
"apc_call_t" => "&dump_apc_call",
|
||||
);
|
||||
|
||||
my @requests = ();
|
||||
|
|
Loading…
Reference in New Issue