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, "," );