server: Add a generic apc_call structure to make it easier to extend, and more type-safe.
diff --git a/server/fd.c b/server/fd.c
index 157db69..d20360a 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1283,8 +1283,15 @@
/* 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;
diff --git a/server/named_pipe.c b/server/named_pipe.c
index 8cbd7e5..9077c58 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -857,9 +857,16 @@
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
diff --git a/server/protocol.def b/server/protocol.def
index 7cde312..a71bcee 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -225,6 +225,34 @@
/* 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 @@
/* 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 @@
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 */
diff --git a/server/thread.c b/server/thread.c
index 630447a..476ee32 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -72,11 +72,7 @@
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 @@
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 @@
}
}
+/* 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 @@
}
/* 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 @@
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 @@
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 );
}
diff --git a/server/thread.h b/server/thread.h
index 0fc162f..e09c11b 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -112,9 +112,8 @@
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 );
diff --git a/server/timer.c b/server/timer.c
index 2640dd8..9ffa649 100644
--- a/server/timer.c
+++ b/server/timer.c
@@ -104,8 +104,20 @@
/* 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 @@
}
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;
}
diff --git a/server/trace.c b/server/trace.c
index 5018423..fcd24e6 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -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 @@
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_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_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 )