Added separate queue for "system" APCs that get called even when the
thread is not in an alertable state.
Specify the select_request timeout as absolute value so that we can
restart the request when interrupted.

diff --git a/include/server.h b/include/server.h
index e6ca2e5..762e272 100644
--- a/include/server.h
+++ b/include/server.h
@@ -340,6 +340,7 @@
 {
     REQUEST_HEADER;                /* request header */
     IN  handle_t     handle;       /* thread handle */
+    IN  int          user;         /* user or system apc? */
     IN  void*        func;         /* function to call */
     IN  void*        param;        /* param for function to call */
 };
@@ -349,6 +350,7 @@
 struct get_apc_request
 {
     REQUEST_HEADER;                /* request header */
+    IN  int          alertable;    /* is thread alertable? */
     OUT void*        func;         /* function to call */
     OUT int          type;         /* function type */
     OUT VARARG(args,ptrs);         /* function arguments */
@@ -412,13 +414,15 @@
 {
     REQUEST_HEADER;                /* request header */
     IN  int          flags;        /* wait flags (see below) */
-    IN  int          timeout;      /* timeout in ms */
+    IN  int          sec;          /* absolute timeout */
+    IN  int          usec;         /* absolute timeout */
     OUT int          signaled;     /* signaled handle */
     IN  VARARG(handles,handles);   /* handles to select on */
 };
-#define SELECT_ALL       1
-#define SELECT_ALERTABLE 2
-#define SELECT_TIMEOUT   4
+#define SELECT_ALL           1
+#define SELECT_ALERTABLE     2
+#define SELECT_INTERRUPTIBLE 4
+#define SELECT_TIMEOUT       8
 
 
 /* Create an event */
@@ -1576,7 +1580,7 @@
     struct async_result_request async_result;
 };
 
-#define SERVER_PROTOCOL_VERSION 33
+#define SERVER_PROTOCOL_VERSION 34
 
 /* ### make_requests end ### */
 /* Everything above this line is generated automatically by tools/make_requests */
diff --git a/scheduler/synchro.c b/scheduler/synchro.c
index 5718b1a..6d42029 100644
--- a/scheduler/synchro.c
+++ b/scheduler/synchro.c
@@ -16,11 +16,30 @@
 
 
 /***********************************************************************
+ *              get_timeout
+ */
+inline static void get_timeout( struct timeval *when, int timeout )
+{
+    gettimeofday( when, 0 );
+    if (timeout)
+    {
+        long sec = timeout / 1000;
+        if ((when->tv_usec += (timeout - 1000*sec) * 1000) >= 1000000)
+        {
+            when->tv_usec -= 1000000;
+            when->tv_sec++;
+        }
+        when->tv_sec += sec;
+    }
+}
+
+
+/***********************************************************************
  *              call_apcs
  *
  * Call outstanding APCs.
  */
-static void call_apcs(void)
+static void call_apcs( BOOL alertable )
 {
     FARPROC proc = NULL;
     FILETIME ft;
@@ -32,6 +51,7 @@
         SERVER_START_REQ
         {
             struct get_apc_request *req = server_alloc_req( sizeof(*req), sizeof(args) );
+            req->alertable = alertable;
             if (!server_call( REQ_GET_APC ))
             {
                 type = req->type;
@@ -119,6 +139,7 @@
                                        BOOL alertable )
 {
     int i, ret;
+    struct timeval tv;
 
     if (count > MAXIMUM_WAIT_OBJECTS)
     {
@@ -126,24 +147,33 @@
         return WAIT_FAILED;
     }
 
-    SERVER_START_REQ
+    if (timeout == INFINITE) tv.tv_sec = tv.tv_usec = 0;
+    else get_timeout( &tv, timeout );
+
+    for (;;)
     {
-        struct select_request *req = server_alloc_req( sizeof(*req), count * sizeof(int) );
-        int *data = server_data_ptr( req );
+        SERVER_START_REQ
+        {
+            struct select_request *req = server_alloc_req( sizeof(*req), count * sizeof(int) );
+            int *data = server_data_ptr( req );
 
-        req->flags   = 0;
-        req->timeout = timeout;
-        for (i = 0; i < count; i++) data[i] = handles[i];
+            req->flags   = SELECT_INTERRUPTIBLE;
+            req->sec     = tv.tv_sec;
+            req->usec    = tv.tv_usec;
+            for (i = 0; i < count; i++) data[i] = handles[i];
 
-        if (wait_all) req->flags |= SELECT_ALL;
-        if (alertable) req->flags |= SELECT_ALERTABLE;
-        if (timeout != INFINITE) req->flags |= SELECT_TIMEOUT;
+            if (wait_all) req->flags |= SELECT_ALL;
+            if (alertable) req->flags |= SELECT_ALERTABLE;
+            if (timeout != INFINITE) req->flags |= SELECT_TIMEOUT;
 
-        server_call( REQ_SELECT );
-        ret = req->signaled;
+            server_call( REQ_SELECT );
+            ret = req->signaled;
+        }
+        SERVER_END_REQ;
+        if (ret != STATUS_USER_APC) break;
+        call_apcs( alertable );
+        if (alertable) break;
     }
-    SERVER_END_REQ;
-    if (ret == STATUS_USER_APC) call_apcs();
     return ret;
 }
 
diff --git a/scheduler/thread.c b/scheduler/thread.c
index cea1156..3735a11 100644
--- a/scheduler/thread.c
+++ b/scheduler/thread.c
@@ -638,6 +638,7 @@
     {
         struct queue_apc_request *req = server_alloc_req( sizeof(*req), 0 );
         req->handle = hthread;
+        req->user   = 1;
         req->func   = func;
         req->param  = (void *)data;
         ret = !server_call( REQ_QUEUE_APC );
diff --git a/server/async.c b/server/async.c
index e740add..838cc6b 100644
--- a/server/async.c
+++ b/server/async.c
@@ -213,25 +213,25 @@
 static void async_poll_event( struct object *obj, int event )
 {
     struct async *ov = (struct async *) obj;
- 
+
     /* queue an APC in the client thread to do our dirty work */
     ov->obj.ops->remove_queue(&ov->obj,&ov->wait);
 
     /* FIXME: this should be a function pointer */
     event = serial_async_poll_event(obj,event);
 
-    thread_queue_apc(ov->thread, NULL, ov->func, APC_ASYNC, 3,
+    thread_queue_apc(ov->thread, NULL, ov->func, APC_ASYNC, 1, 3,
                      ov->client_overlapped, ov->buffer, event);
-} 
+}
 
 /* handler for async i/o timeouts */
 static void overlapped_timeout (void *private)
 {
     struct async *ov = (struct async *) private;
- 
+
     ov->obj.ops->remove_queue(&ov->obj,&ov->wait);
- 
-    thread_queue_apc(ov->thread, NULL, ov->func, APC_ASYNC, 3,
+
+    thread_queue_apc(ov->thread, NULL, ov->func, APC_ASYNC, 1, 3,
                      ov->client_overlapped,ov->buffer, 0);
 }
 
diff --git a/server/debugger.c b/server/debugger.c
index 202f0dd..32ca8d5 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -363,14 +363,21 @@
     struct debug_ctx *debug_ctx = current->debug_ctx;
     struct object *obj = &debug_ctx->obj;
     int flags = 0;
+    struct timeval tv;
 
     if (!debug_ctx)  /* current thread is not a debugger */
     {
         set_error( STATUS_INVALID_HANDLE );
         return 0;
     }
-    if (timeout != -1) flags = SELECT_TIMEOUT;
-    return sleep_on( 1, &obj, flags, timeout, build_wait_debug_reply );
+    if (timeout != -1)
+    {
+        flags = SELECT_TIMEOUT;
+        gettimeofday( &tv, 0 );
+        add_timeout( &tv, timeout );
+    }
+    else tv.tv_sec = tv.tv_usec = 0;
+    return sleep_on( 1, &obj, flags, tv.tv_sec, tv.tv_usec, build_wait_debug_reply );
 }
 
 /* continue a debug event */
@@ -603,7 +610,7 @@
         {
             struct object *obj = &event->obj;
             current->context = context;
-            sleep_on( 1, &obj, 0, -1, build_exception_event_reply );
+            sleep_on( 1, &obj, 0, 0, 0, build_exception_event_reply );
             release_object( event );
         }
     }
diff --git a/server/process.c b/server/process.c
index 1a84c40..bab1043 100644
--- a/server/process.c
+++ b/server/process.c
@@ -771,8 +771,12 @@
     }
     else
     {
+        struct timeval timeout;
         struct object *obj = &current->info->obj;
-        sleep_on( 1, &obj, SELECT_TIMEOUT, req->timeout, build_wait_process_reply );
+        gettimeofday( &timeout, 0 );
+        add_timeout( &timeout, req->timeout );
+        sleep_on( 1, &obj, SELECT_TIMEOUT, timeout.tv_sec, timeout.tv_usec,
+                  build_wait_process_reply );
     }
 }
 
diff --git a/server/thread.c b/server/thread.c
index fceca02..31e3ff0 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -64,7 +64,7 @@
 static int thread_signaled( struct object *obj, struct thread *thread );
 extern void thread_poll_event( struct object *obj, int event );
 static void destroy_thread( struct object *obj );
-static struct thread_apc *thread_dequeue_apc( struct thread *thread );
+static struct thread_apc *thread_dequeue_apc( struct thread *thread, int system_only );
 
 static const struct object_ops thread_ops =
 {
@@ -147,8 +147,10 @@
     thread->queue       = NULL;
     thread->info        = NULL;
     thread->wait        = NULL;
-    thread->apc_head    = NULL;
-    thread->apc_tail    = NULL;
+    thread->system_apc.head = NULL;
+    thread->system_apc.tail = NULL;
+    thread->user_apc.head   = NULL;
+    thread->user_apc.tail   = NULL;
     thread->error       = 0;
     thread->pass_fd     = -1;
     thread->request_fd  = NULL;
@@ -211,7 +213,7 @@
     if (thread->next) thread->next->prev = thread->prev;
     if (thread->prev) thread->prev->next = thread->next;
     else first_thread = thread->next;
-    while ((apc = thread_dequeue_apc( thread ))) free( apc );
+    while ((apc = thread_dequeue_apc( thread, 0 ))) free( apc );
     if (thread->info) release_object( thread->info );
     if (thread->queue) release_object( thread->queue );
     if (thread->buffer != (void *)-1) munmap( thread->buffer, MAX_REQUEST_LENGTH );
@@ -354,7 +356,7 @@
 
 /* build the thread wait structure */
 static int wait_on( int count, struct object *objects[], int flags,
-                    int timeout, sleep_reply func )
+                    int sec, int usec, sleep_reply func )
 {
     struct thread_wait *wait;
     struct wait_queue_entry *entry;
@@ -368,8 +370,8 @@
     wait->reply   = func;
     if (flags & SELECT_TIMEOUT)
     {
-        gettimeofday( &wait->timeout, 0 );
-        add_timeout( &wait->timeout, timeout );
+        wait->timeout.tv_sec = sec;
+        wait->timeout.tv_usec = usec;
     }
 
     for (i = 0, entry = wait->queues; i < count; i++, entry++)
@@ -425,7 +427,8 @@
     }
 
  other_checks:
-    if ((wait->flags & SELECT_ALERTABLE) && thread->apc_head) return STATUS_USER_APC;
+    if ((wait->flags & SELECT_INTERRUPTIBLE) && thread->system_apc.head) return STATUS_USER_APC;
+    if ((wait->flags & SELECT_ALERTABLE) && thread->user_apc.head) return STATUS_USER_APC;
     if (wait->flags & SELECT_TIMEOUT)
     {
         struct timeval now;
@@ -469,10 +472,10 @@
 }
 
 /* sleep on a list of objects */
-int sleep_on( int count, struct object *objects[], int flags, int timeout, sleep_reply func )
+int sleep_on( int count, struct object *objects[], int flags, int sec, int usec, sleep_reply func )
 {
     assert( !current->wait );
-    if (!wait_on( count, objects, flags, timeout, func )) return 0;
+    if (!wait_on( count, objects, flags, sec, usec, func )) return 0;
     if (wake_thread( current )) return 1;
     /* now we need to wait */
     if (flags & SELECT_TIMEOUT)
@@ -488,7 +491,7 @@
 }
 
 /* select on a list of handles */
-static int select_on( int count, handle_t *handles, int flags, int timeout )
+static int select_on( int count, handle_t *handles, int flags, int sec, int usec )
 {
     int ret = 0;
     int i;
@@ -504,7 +507,7 @@
         if (!(objects[i] = get_handle_obj( current->process, handles[i], SYNCHRONIZE, NULL )))
             break;
     }
-    if (i == count) ret = sleep_on( count, objects, flags, timeout, build_select_reply );
+    if (i == count) ret = sleep_on( count, objects, flags, sec, usec, build_select_reply );
     while (--i >= 0) release_object( objects[i] );
     return ret;
 }
@@ -528,15 +531,16 @@
 
 /* queue an async procedure call */
 int thread_queue_apc( struct thread *thread, struct object *owner, void *func,
-                      enum apc_type type, int nb_args, ... )
+                      enum apc_type type, int system, int nb_args, ... )
 {
     struct thread_apc *apc;
+    struct apc_queue *queue = system ? &thread->system_apc : &thread->user_apc;
 
     /* cancel a possible previous APC with the same owner */
-    if (owner) thread_cancel_apc( thread, owner );
+    if (owner) thread_cancel_apc( thread, owner, system );
 
     if (!(apc = mem_alloc( sizeof(*apc) + (nb_args-1)*sizeof(apc->args[0]) ))) return 0;
-    apc->prev    = thread->apc_tail;
+    apc->prev    = queue->tail;
     apc->next    = NULL;
     apc->owner   = owner;
     apc->func    = func;
@@ -550,40 +554,44 @@
         for (i = 0; i < nb_args; i++) apc->args[i] = va_arg( args, void * );
         va_end( args );
     }
-    thread->apc_tail = apc;
+    queue->tail = apc;
     if (!apc->prev)  /* first one */
     {
-        thread->apc_head = apc;
+        queue->head = apc;
         if (thread->wait && wake_thread( thread )) send_reply( thread );
     }
     return 1;
 }
 
 /* cancel the async procedure call owned by a specific object */
-void thread_cancel_apc( struct thread *thread, struct object *owner )
+void thread_cancel_apc( struct thread *thread, struct object *owner, int system )
 {
     struct thread_apc *apc;
-    for (apc = thread->apc_head; apc; apc = apc->next)
+    struct apc_queue *queue = system ? &thread->system_apc : &thread->user_apc;
+    for (apc = queue->head; apc; apc = apc->next)
     {
         if (apc->owner != owner) continue;
         if (apc->next) apc->next->prev = apc->prev;
-        else thread->apc_tail = apc->prev;
+        else queue->tail = apc->prev;
         if (apc->prev) apc->prev->next = apc->next;
-        else thread->apc_head = apc->next;
+        else queue->head = apc->next;
         free( apc );
         return;
     }
 }
 
 /* remove the head apc from the queue; the returned pointer must be freed by the caller */
-static struct thread_apc *thread_dequeue_apc( struct thread *thread )
+static struct thread_apc *thread_dequeue_apc( struct thread *thread, int system_only )
 {
-    struct thread_apc *apc = thread->apc_head;
-    if (apc)
+    struct thread_apc *apc;
+    struct apc_queue *queue = &thread->system_apc;
+
+    if (!queue->head && !system_only) queue = &thread->user_apc;
+    if ((apc = queue->head))
     {
         if (apc->next) apc->next->prev = NULL;
-        else thread->apc_tail = NULL;
-        thread->apc_head = apc->next;
+        else queue->tail = NULL;
+        queue->head = apc->next;
     }
     return apc;
 }
@@ -811,7 +819,7 @@
 DECL_HANDLER(select)
 {
     int count = get_req_data_size(req) / sizeof(int);
-    if (!select_on( count, get_req_data(req), req->flags, req->timeout ))
+    if (!select_on( count, get_req_data(req), req->flags, req->sec, req->usec ))
         req->signaled = -1;
 }
 
@@ -821,7 +829,7 @@
     struct thread *thread;
     if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
     {
-        thread_queue_apc( thread, NULL, req->func, APC_USER, 1, req->param );
+        thread_queue_apc( thread, NULL, req->func, APC_USER, !req->user, 1, req->param );
         release_object( thread );
     }
 }
@@ -834,7 +842,7 @@
 
     for (;;)
     {
-        if (!(apc = thread_dequeue_apc( current )))
+        if (!(apc = thread_dequeue_apc( current, !req->alertable )))
         {
             /* no more APCs */
             req->func    = NULL;
diff --git a/server/thread.h b/server/thread.h
index 0eea735..4b5aa11 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -30,6 +30,11 @@
     TERMINATED  /* terminated */
 };
 
+struct apc_queue
+{
+    struct thread_apc *head;
+    struct thread_apc *tail;
+};
 
 struct thread
 {
@@ -45,8 +50,8 @@
     struct msg_queue   *queue;       /* message queue */
     struct startup_info*info;        /* startup info for child process */
     struct thread_wait *wait;        /* current wait condition if sleeping */
-    struct thread_apc  *apc_head;    /* queue of async procedure calls */
-    struct thread_apc  *apc_tail;    /* queue of async procedure calls */
+    struct apc_queue    system_apc;  /* queue of system async procedure calls */
+    struct apc_queue    user_apc;    /* queue of user async procedure calls */
     unsigned int        error;       /* current error code */
     struct object      *request_fd;  /* fd for receiving client requests */
     int                 pass_fd;     /* fd to pass to the client */
@@ -92,10 +97,10 @@
 extern void kill_thread( struct thread *thread, int violent_death );
 extern void wake_up( struct object *obj, int max );
 extern int sleep_on( int count, struct object *objects[], int flags,
-                     int timeout, sleep_reply func );
+                     int sec, int usec, sleep_reply func );
 extern int thread_queue_apc( struct thread *thread, struct object *owner, void *func,
-                             enum apc_type type, int nb_args, ... );
-extern void thread_cancel_apc( struct thread *thread, struct object *owner );
+                             enum apc_type type, int system, int nb_args, ... );
+extern void thread_cancel_apc( struct thread *thread, struct object *owner, int system );
 extern struct thread_snapshot *thread_snap( int *count );
 
 /* ptrace functions */
diff --git a/server/timer.c b/server/timer.c
index f4b159f..a76ce41 100644
--- a/server/timer.c
+++ b/server/timer.c
@@ -78,7 +78,7 @@
 
     /* queue an APC */
     if (timer->thread)
-        thread_queue_apc( timer->thread, &timer->obj, timer->callback, APC_TIMER, 3,
+        thread_queue_apc( timer->thread, &timer->obj, timer->callback, APC_TIMER, 0, 3,
                           (void *)timer->when.tv_sec, (void *)timer->when.tv_usec, timer->arg );
 
     if (timer->period)  /* schedule the next expiration */
@@ -103,7 +103,7 @@
     }
     if (timer->thread)
     {
-        thread_cancel_apc( timer->thread, &timer->obj );
+        thread_cancel_apc( timer->thread, &timer->obj, 0 );
         timer->thread = NULL;
     }
 }
diff --git a/server/trace.c b/server/trace.c
index 59d9a29..76c7bdf 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -466,12 +466,14 @@
 static void dump_queue_apc_request( const struct queue_apc_request *req )
 {
     fprintf( stderr, " handle=%d,", req->handle );
+    fprintf( stderr, " user=%d,", req->user );
     fprintf( stderr, " func=%p,", req->func );
     fprintf( stderr, " param=%p", req->param );
 }
 
 static void dump_get_apc_request( const struct get_apc_request *req )
 {
+    fprintf( stderr, " alertable=%d", req->alertable );
 }
 
 static void dump_get_apc_reply( const struct get_apc_request *req )
@@ -537,7 +539,8 @@
 static void dump_select_request( const struct select_request *req )
 {
     fprintf( stderr, " flags=%d,", req->flags );
-    fprintf( stderr, " timeout=%d,", req->timeout );
+    fprintf( stderr, " sec=%d,", req->sec );
+    fprintf( stderr, " usec=%d,", req->usec );
     fprintf( stderr, " handles=" );
     cur_pos += dump_varargs_handles( req );
 }