Implemented NtSignalAndWaitForSingleObject.

diff --git a/server/atom.c b/server/atom.c
index e14c05e..341cf6b 100644
--- a/server/atom.c
+++ b/server/atom.c
@@ -70,7 +70,8 @@
     no_add_queue,                 /* add_queue */
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
-    NULL,                         /* satified */
+    NULL,                         /* satisfied */
+    no_signal,                    /* signal */
     no_get_fd,                    /* get_fd */
     atom_table_destroy            /* destroy */
 };
diff --git a/server/change.c b/server/change.c
index 2d42644..51867dd 100644
--- a/server/change.c
+++ b/server/change.c
@@ -71,6 +71,7 @@
     remove_queue,             /* remove_queue */
     change_signaled,          /* signaled */
     no_satisfied,             /* satisfied */
+    no_signal,                /* signal */
     no_get_fd,                /* get_fd */
     change_destroy            /* destroy */
 };
diff --git a/server/console.c b/server/console.c
index b51f56d..a513538 100644
--- a/server/console.c
+++ b/server/console.c
@@ -46,6 +46,7 @@
     NULL,                             /* remove_queue */
     NULL,                             /* signaled */
     no_satisfied,                     /* satisfied */
+    no_signal,                        /* signal */
     no_get_fd,                        /* get_fd */
     console_input_destroy             /* destroy */
 };
@@ -70,6 +71,7 @@
     remove_queue,                     /* remove_queue */
     console_input_events_signaled,    /* signaled */
     no_satisfied,                     /* satisfied */
+    no_signal,                        /* signal */
     no_get_fd,                        /* get_fd */
     console_input_events_destroy      /* destroy */
 };
@@ -105,6 +107,7 @@
     NULL,                             /* remove_queue */
     NULL,                             /* signaled */
     NULL,                             /* satisfied */
+    no_signal,                        /* signal */
     no_get_fd,                        /* get_fd */
     screen_buffer_destroy             /* destroy */
 };
diff --git a/server/debugger.c b/server/debugger.c
index bde88a2..b1ba9b1 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -72,6 +72,7 @@
     remove_queue,                  /* remove_queue */
     debug_event_signaled,          /* signaled */
     no_satisfied,                  /* satisfied */
+    no_signal,                     /* signal */
     no_get_fd,                     /* get_fd */
     debug_event_destroy            /* destroy */
 };
@@ -88,6 +89,7 @@
     remove_queue,                  /* remove_queue */
     debug_ctx_signaled,            /* signaled */
     no_satisfied,                  /* satisfied */
+    no_signal,                     /* signal */
     no_get_fd,                     /* get_fd */
     debug_ctx_destroy              /* destroy */
 };
diff --git a/server/event.c b/server/event.c
index e1487d3..fa1dbbf 100644
--- a/server/event.c
+++ b/server/event.c
@@ -41,6 +41,7 @@
 static void event_dump( struct object *obj, int verbose );
 static int event_signaled( struct object *obj, struct thread *thread );
 static int event_satisfied( struct object *obj, struct thread *thread );
+static int event_signal( struct object *obj, unsigned int access);
 
 static const struct object_ops event_ops =
 {
@@ -50,6 +51,7 @@
     remove_queue,              /* remove_queue */
     event_signaled,            /* signaled */
     event_satisfied,           /* satisfied */
+    event_signal,              /* signal */
     no_get_fd,                 /* get_fd */
     no_destroy                 /* destroy */
 };
@@ -123,6 +125,20 @@
     return 0;  /* Not abandoned */
 }
 
+static int event_signal( struct object *obj, unsigned int access )
+{
+    struct event *event = (struct event *)obj;
+    assert( obj->ops == &event_ops );
+
+    if (!(access & EVENT_MODIFY_STATE))
+    {
+        set_error( STATUS_ACCESS_DENIED );
+        return 0;
+    }
+    set_event( event );
+    return 1;
+}
+
 /* create an event */
 DECL_HANDLER(create_event)
 {
diff --git a/server/fd.c b/server/fd.c
index ef5b31c..72c3d9f 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -159,6 +159,7 @@
     NULL,                     /* remove_queue */
     NULL,                     /* signaled */
     NULL,                     /* satisfied */
+    no_signal,                /* signal */
     no_get_fd,                /* get_fd */
     fd_destroy                /* destroy */
 };
@@ -188,6 +189,7 @@
     NULL,                     /* remove_queue */
     NULL,                     /* signaled */
     NULL,                     /* satisfied */
+    no_signal,                /* signal */
     no_get_fd,                /* get_fd */
     inode_destroy             /* destroy */
 };
@@ -218,6 +220,7 @@
     remove_queue,               /* remove_queue */
     file_lock_signaled,         /* signaled */
     no_satisfied,               /* satisfied */
+    no_signal,                  /* signal */
     no_get_fd,                  /* get_fd */
     no_destroy                  /* destroy */
 };
diff --git a/server/file.c b/server/file.c
index d28dc0d..45f2bc0 100644
--- a/server/file.c
+++ b/server/file.c
@@ -83,6 +83,7 @@
     default_fd_remove_queue,      /* remove_queue */
     default_fd_signaled,          /* signaled */
     no_satisfied,                 /* satisfied */
+    no_signal,                    /* signal */
     file_get_fd,                  /* get_fd */
     file_destroy                  /* destroy */
 };
diff --git a/server/handle.c b/server/handle.c
index ae68a7a..347960d 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -106,6 +106,7 @@
     NULL,                            /* remove_queue */
     NULL,                            /* signaled */
     NULL,                            /* satisfied */
+    no_signal,                       /* signal */
     no_get_fd,                       /* get_fd */
     handle_table_destroy             /* destroy */
 };
@@ -385,6 +386,16 @@
     return grab_object( obj );
 }
 
+/* retrieve the access rights of a given handle */
+unsigned int get_handle_access( struct process *process, obj_handle_t handle )
+{
+    struct handle_entry *entry;
+
+    if (get_magic_handle( handle )) return ~0U;  /* magic handles have all access rights */
+    if (!(entry = get_handle( process, handle ))) return 0;
+    return entry->access;
+}
+
 /* retrieve the cached fd for a given handle */
 int get_handle_unix_fd( struct process *process, obj_handle_t handle, unsigned int access )
 {
diff --git a/server/handle.h b/server/handle.h
index 91b7a2c..84faae1 100644
--- a/server/handle.h
+++ b/server/handle.h
@@ -38,6 +38,7 @@
 extern int close_handle( struct process *process, obj_handle_t handle, int *fd );
 extern struct object *get_handle_obj( struct process *process, obj_handle_t handle,
                                       unsigned int access, const struct object_ops *ops );
+extern unsigned int get_handle_access( struct process *process, obj_handle_t handle );
 extern int get_handle_unix_fd( struct process *process, obj_handle_t handle, unsigned int access );
 extern int set_handle_info( struct process *process, obj_handle_t handle, int mask, int flags, int *fd );
 extern obj_handle_t duplicate_handle( struct process *src, obj_handle_t src_handle, struct process *dst,
diff --git a/server/hook.c b/server/hook.c
index 293b20c..c228f98 100644
--- a/server/hook.c
+++ b/server/hook.c
@@ -77,6 +77,7 @@
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
     NULL,                         /* satisfied */
+    no_signal,                    /* signal */
     no_get_fd,                    /* get_fd */
     hook_table_destroy            /* destroy */
 };
diff --git a/server/mailslot.c b/server/mailslot.c
index 7a6230f..4066e57 100644
--- a/server/mailslot.c
+++ b/server/mailslot.c
@@ -72,6 +72,7 @@
     default_fd_remove_queue,   /* remove_queue */
     default_fd_signaled,       /* signaled */
     no_satisfied,              /* satisfied */
+    no_signal,                 /* signal */
     mailslot_get_fd,           /* get_fd */
     mailslot_destroy           /* destroy */
 };
@@ -113,6 +114,7 @@
     NULL,                       /* remove_queue */
     NULL,                       /* signaled */
     NULL,                       /* satisfied */
+    no_signal,                  /* signal */
     mail_writer_get_fd,         /* get_fd */
     mail_writer_destroy         /* destroy */
 };
diff --git a/server/mapping.c b/server/mapping.c
index 8992986..046bc0b 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -62,6 +62,7 @@
     NULL,                        /* remove_queue */
     NULL,                        /* signaled */
     NULL,                        /* satisfied */
+    no_signal,                   /* signal */
     mapping_get_fd,              /* get_fd */
     mapping_destroy              /* destroy */
 };
diff --git a/server/mutex.c b/server/mutex.c
index 1b1ef37..c1b59bb 100644
--- a/server/mutex.c
+++ b/server/mutex.c
@@ -44,6 +44,7 @@
 static int mutex_signaled( struct object *obj, struct thread *thread );
 static int mutex_satisfied( struct object *obj, struct thread *thread );
 static void mutex_destroy( struct object *obj );
+static int mutex_signal( struct object *obj, unsigned int access );
 
 static const struct object_ops mutex_ops =
 {
@@ -53,6 +54,7 @@
     remove_queue,              /* remove_queue */
     mutex_signaled,            /* signaled */
     mutex_satisfied,           /* satisfied */
+    mutex_signal,              /* signal */
     no_get_fd,                 /* get_fd */
     mutex_destroy              /* destroy */
 };
@@ -133,6 +135,25 @@
     return 1;
 }
 
+static int mutex_signal( struct object *obj, unsigned int access )
+{
+    struct mutex *mutex = (struct mutex *)obj;
+    assert( obj->ops == &mutex_ops );
+
+    if (!(access & SYNCHRONIZE))  /* FIXME: MUTEX_MODIFY_STATE? */
+    {
+        set_error( STATUS_ACCESS_DENIED );
+        return 0;
+    }
+    if (!mutex->count || (mutex->owner != current))
+    {
+        set_error( STATUS_MUTANT_NOT_OWNED );
+        return 0;
+    }
+    if (!--mutex->count) do_release( mutex );
+    return 1;
+}
+
 static void mutex_destroy( struct object *obj )
 {
     struct mutex *mutex = (struct mutex *)obj;
diff --git a/server/named_pipe.c b/server/named_pipe.c
index dd1d3dd..b5077be 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -106,6 +106,7 @@
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
     NULL,                         /* satisfied */
+    no_signal,                    /* signal */
     no_get_fd,                    /* get_fd */
     named_pipe_destroy            /* destroy */
 };
@@ -128,6 +129,7 @@
     default_fd_remove_queue,      /* remove_queue */
     default_fd_signaled,          /* signaled */
     no_satisfied,                 /* satisfied */
+    no_signal,                    /* signal */
     pipe_server_get_fd,           /* get_fd */
     pipe_server_destroy           /* destroy */
 };
@@ -156,6 +158,7 @@
     default_fd_remove_queue,      /* remove_queue */
     default_fd_signaled,          /* signaled */
     no_satisfied,                 /* satisfied */
+    no_signal,                    /* signal */
     pipe_client_get_fd,           /* get_fd */
     pipe_client_destroy           /* destroy */
 };
diff --git a/server/object.c b/server/object.c
index 91959b6..479b09c 100644
--- a/server/object.c
+++ b/server/object.c
@@ -273,6 +273,12 @@
     return 0;  /* not abandoned */
 }
 
+int no_signal( struct object *obj, unsigned int access )
+{
+    set_error( STATUS_OBJECT_TYPE_MISMATCH );
+    return 0;
+}
+
 struct fd *no_get_fd( struct object *obj )
 {
     set_error( STATUS_OBJECT_TYPE_MISMATCH );
diff --git a/server/object.h b/server/object.h
index 44dfe18..e886526 100644
--- a/server/object.h
+++ b/server/object.h
@@ -59,6 +59,8 @@
     int  (*signaled)(struct object *,struct thread *);
     /* wait satisfied; return 1 if abandoned */
     int  (*satisfied)(struct object *,struct thread *);
+    /* signal an object */
+    int  (*signal)(struct object *, unsigned int);
     /* return an fd object that can be used to read/write from the object */
     struct fd *(*get_fd)(struct object *);
     /* destroy on refcount == 0 */
@@ -97,6 +99,7 @@
 extern struct object *find_object( const struct namespace *namespace, const WCHAR *name, size_t len );
 extern int no_add_queue( struct object *obj, struct wait_queue_entry *entry );
 extern int no_satisfied( struct object *obj, struct thread *thread );
+extern int no_signal( struct object *obj, unsigned int access );
 extern struct fd *no_get_fd( struct object *obj );
 extern void no_destroy( struct object *obj );
 #ifdef DEBUG_OBJECTS
diff --git a/server/process.c b/server/process.c
index 12f9a1e..d2f8c89 100644
--- a/server/process.c
+++ b/server/process.c
@@ -70,6 +70,7 @@
     remove_queue,                /* remove_queue */
     process_signaled,            /* signaled */
     no_satisfied,                /* satisfied */
+    no_signal,                    /* signal */
     no_get_fd,                   /* get_fd */
     process_destroy              /* destroy */
 };
@@ -116,6 +117,7 @@
     remove_queue,                  /* remove_queue */
     startup_info_signaled,         /* signaled */
     no_satisfied,                  /* satisfied */
+    no_signal,                     /* signal */
     no_get_fd,                     /* get_fd */
     startup_info_destroy           /* destroy */
 };
diff --git a/server/protocol.def b/server/protocol.def
index 3427fd0..fe89218 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -480,6 +480,7 @@
 @REQ(select)
     int          flags;        /* wait flags (see below) */
     void*        cookie;       /* magic cookie to return to client */
+    obj_handle_t signal;       /* object to signal (0 if none) */
     abs_time_t   timeout;      /* absolute timeout */
     VARARG(handles,handles);   /* handles to select on */
 @END
diff --git a/server/queue.c b/server/queue.c
index e801fb0..c2fb9a9 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -146,6 +146,7 @@
     msg_queue_remove_queue,    /* remove_queue */
     msg_queue_signaled,        /* signaled */
     msg_queue_satisfied,       /* satisfied */
+    no_signal,                 /* signal */
     no_get_fd,                 /* get_fd */
     msg_queue_destroy          /* destroy */
 };
@@ -159,6 +160,7 @@
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
     NULL,                         /* satisfied */
+    no_signal,                    /* signal */
     no_get_fd,                    /* get_fd */
     thread_input_destroy          /* destroy */
 };
diff --git a/server/registry.c b/server/registry.c
index 6f85f57..c7dcd73 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -138,6 +138,7 @@
     NULL,                    /* remove_queue */
     NULL,                    /* signaled */
     NULL,                    /* satisfied */
+    no_signal,               /* signal */
     no_get_fd,               /* get_fd */
     key_destroy              /* destroy */
 };
diff --git a/server/request.c b/server/request.c
index 4f943d0..8d33660 100644
--- a/server/request.c
+++ b/server/request.c
@@ -93,6 +93,7 @@
     NULL,                          /* remove_queue */
     NULL,                          /* signaled */
     NULL,                          /* satisfied */
+    no_signal,                     /* signal */
     no_get_fd,                     /* get_fd */
     master_socket_destroy          /* destroy */
 };
diff --git a/server/semaphore.c b/server/semaphore.c
index 27aba0d..7886842 100644
--- a/server/semaphore.c
+++ b/server/semaphore.c
@@ -41,6 +41,7 @@
 static void semaphore_dump( struct object *obj, int verbose );
 static int semaphore_signaled( struct object *obj, struct thread *thread );
 static int semaphore_satisfied( struct object *obj, struct thread *thread );
+static int semaphore_signal( struct object *obj, unsigned int access );
 
 static const struct object_ops semaphore_ops =
 {
@@ -50,6 +51,7 @@
     remove_queue,                  /* remove_queue */
     semaphore_signaled,            /* signaled */
     semaphore_satisfied,           /* satisfied */
+    semaphore_signal,              /* signal */
     no_get_fd,                     /* get_fd */
     no_destroy                     /* destroy */
 };
@@ -77,32 +79,26 @@
     return sem;
 }
 
-static unsigned int release_semaphore( obj_handle_t handle, unsigned int count )
+static int release_semaphore( struct semaphore *sem, unsigned int count,
+                              unsigned int *prev )
 {
-    struct semaphore *sem;
-    unsigned int prev = 0;
-
-    if ((sem = (struct semaphore *)get_handle_obj( current->process, handle,
-                                                   SEMAPHORE_MODIFY_STATE, &semaphore_ops )))
+    if (prev) *prev = sem->count;
+    if (sem->count + count < sem->count || sem->count + count > sem->max)
     {
-        prev = sem->count;
-        if (sem->count + count < sem->count || sem->count + count > sem->max)
-        {
-            set_error( STATUS_SEMAPHORE_LIMIT_EXCEEDED );
-        }
-        else if (sem->count)
-        {
-            /* there cannot be any thread to wake up if the count is != 0 */
-            sem->count += count;
-        }
-        else
-        {
-            sem->count = count;
-            wake_up( &sem->obj, count );
-        }
-        release_object( sem );
+        set_error( STATUS_SEMAPHORE_LIMIT_EXCEEDED );
+        return 0;
     }
-    return prev;
+    else if (sem->count)
+    {
+        /* there cannot be any thread to wake up if the count is != 0 */
+        sem->count += count;
+    }
+    else
+    {
+        sem->count = count;
+        wake_up( &sem->obj, count );
+    }
+    return 1;
 }
 
 static void semaphore_dump( struct object *obj, int verbose )
@@ -130,6 +126,19 @@
     return 0;  /* not abandoned */
 }
 
+static int semaphore_signal( struct object *obj, unsigned int access )
+{
+    struct semaphore *sem = (struct semaphore *)obj;
+    assert( obj->ops == &semaphore_ops );
+
+    if (!(access & SEMAPHORE_MODIFY_STATE))
+    {
+        set_error( STATUS_ACCESS_DENIED );
+        return 0;
+    }
+    return release_semaphore( sem, 1, NULL );
+}
+
 /* create a semaphore */
 DECL_HANDLER(create_semaphore)
 {
@@ -154,5 +163,12 @@
 /* release a semaphore */
 DECL_HANDLER(release_semaphore)
 {
-    reply->prev_count = release_semaphore( req->handle, req->count );
+    struct semaphore *sem;
+
+    if ((sem = (struct semaphore *)get_handle_obj( current->process, req->handle,
+                                                   SEMAPHORE_MODIFY_STATE, &semaphore_ops )))
+    {
+        release_semaphore( sem, req->count, &reply->prev_count );
+        release_object( sem );
+    }
 }
diff --git a/server/serial.c b/server/serial.c
index 6f90f5f..014142e 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -101,6 +101,7 @@
     default_fd_remove_queue,      /* remove_queue */
     default_fd_signaled,          /* signaled */
     no_satisfied,                 /* satisfied */
+    no_signal,                    /* signal */
     serial_get_fd,                /* get_fd */
     serial_destroy                /* destroy */
 };
diff --git a/server/signal.c b/server/signal.c
index ea1c15b..470a476 100644
--- a/server/signal.c
+++ b/server/signal.c
@@ -62,6 +62,7 @@
     NULL,                     /* remove_queue */
     NULL,                     /* signaled */
     NULL,                     /* satisfied */
+    no_signal,                /* signal */
     no_get_fd,                /* get_fd */
     handler_destroy           /* destroy */
 };
diff --git a/server/snapshot.c b/server/snapshot.c
index 975728a..61265ba 100644
--- a/server/snapshot.c
+++ b/server/snapshot.c
@@ -61,6 +61,7 @@
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
     NULL,                         /* satisfied */
+    no_signal,                    /* signal */
     no_get_fd,                    /* get_fd */
     snapshot_destroy              /* destroy */
 };
diff --git a/server/sock.c b/server/sock.c
index f3f27fc..7fcb406 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -107,6 +107,7 @@
     remove_queue,                 /* remove_queue */
     sock_signaled,                /* signaled */
     no_satisfied,                 /* satisfied */
+    no_signal,                    /* signal */
     sock_get_fd,                  /* get_fd */
     sock_destroy                  /* destroy */
 };
diff --git a/server/thread.c b/server/thread.c
index af6657e..2d7a61b 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -92,6 +92,7 @@
     remove_queue,               /* remove_queue */
     thread_signaled,            /* signaled */
     no_satisfied,               /* satisfied */
+    no_signal,                  /* signal */
     no_get_fd,                  /* get_fd */
     destroy_thread              /* destroy */
 };
@@ -516,9 +517,24 @@
     wake_thread( thread );
 }
 
+/* try signaling an event flag, a semaphore or a mutex */
+static int signal_object( obj_handle_t handle )
+{
+    struct object *obj;
+    int ret = 0;
+
+    obj = get_handle_obj( current->process, handle, 0, NULL );
+    if (obj)
+    {
+        ret = obj->ops->signal( obj, get_handle_access( current->process, handle ));
+        release_object( obj );
+    }
+    return ret;
+}
+
 /* select on a list of handles */
 static void select_on( int count, void *cookie, const obj_handle_t *handles,
-                       int flags, const abs_time_t *timeout )
+                       int flags, const abs_time_t *timeout, obj_handle_t signal_obj )
 {
     int ret, i;
     struct object *objects[MAXIMUM_WAIT_OBJECTS];
@@ -537,6 +553,18 @@
     if (i < count) goto done;
     if (!wait_on( count, objects, flags, timeout )) goto done;
 
+    /* signal the object */
+    if (signal_obj)
+    {
+        if (!signal_object( signal_obj ))
+        {
+            end_wait( current );
+            goto done;
+        }
+        /* check if we woke ourselves up */
+        if (!current->wait) goto done;
+    }
+
     if ((ret = check_wait( current )) != -1)
     {
         /* condition is already satisfied */
@@ -962,7 +990,7 @@
 DECL_HANDLER(select)
 {
     int count = get_req_data_size() / sizeof(int);
-    select_on( count, req->cookie, get_req_data(), req->flags, &req->timeout );
+    select_on( count, req->cookie, get_req_data(), req->flags, &req->timeout, req->signal );
 }
 
 /* queue an APC for a thread */
diff --git a/server/timer.c b/server/timer.c
index 1903ba7..720c6f3 100644
--- a/server/timer.c
+++ b/server/timer.c
@@ -59,6 +59,7 @@
     remove_queue,              /* remove_queue */
     timer_signaled,            /* signaled */
     timer_satisfied,           /* satisfied */
+    no_signal,                 /* signal */
     no_get_fd,                 /* get_fd */
     timer_destroy              /* destroy */
 };
diff --git a/server/token.c b/server/token.c
index 23fe27c..e30f755 100644
--- a/server/token.c
+++ b/server/token.c
@@ -79,7 +79,8 @@
     no_add_queue,              /* add_queue */
     NULL,                      /* remove_queue */
     NULL,                      /* signaled */
-    NULL,                      /* satified */
+    NULL,                      /* satisfied */
+    no_signal,                 /* signal */
     no_get_fd,                 /* get_fd */
     token_destroy              /* destroy */
 };
diff --git a/server/trace.c b/server/trace.c
index d12c962..2de4ddf 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -760,6 +760,7 @@
 {
     fprintf( stderr, " flags=%d,", req->flags );
     fprintf( stderr, " cookie=%p,", req->cookie );
+    fprintf( stderr, " signal=%p,", req->signal );
     fprintf( stderr, " timeout=" );
     dump_abs_time( &req->timeout );
     fprintf( stderr, "," );