From f92fff66a2462c90c89a09b08c1920faa01f6592 Mon Sep 17 00:00:00 2001 From: Mike McCormack <mike@codeweavers.com> Date: Sun, 24 Apr 2005 17:35:52 +0000 Subject: [PATCH] Implemented NtSignalAndWaitForSingleObject. --- dlls/ntdll/ntdll_misc.h | 2 +- dlls/ntdll/signal_i386.c | 2 +- dlls/ntdll/sync.c | 33 ++++++++++-------- include/wine/server_protocol.h | 3 +- include/winternl.h | 2 +- server/atom.c | 3 +- server/change.c | 1 + server/console.c | 3 ++ server/debugger.c | 2 ++ server/event.c | 16 +++++++++ server/fd.c | 3 ++ server/file.c | 1 + server/handle.c | 11 ++++++ server/handle.h | 1 + server/hook.c | 1 + server/mailslot.c | 2 ++ server/mapping.c | 1 + server/mutex.c | 21 +++++++++++ server/named_pipe.c | 3 ++ server/object.c | 6 ++++ server/object.h | 3 ++ server/process.c | 2 ++ server/protocol.def | 1 + server/queue.c | 2 ++ server/registry.c | 1 + server/request.c | 1 + server/semaphore.c | 64 +++++++++++++++++++++------------- server/serial.c | 1 + server/signal.c | 1 + server/snapshot.c | 1 + server/sock.c | 1 + server/thread.c | 32 +++++++++++++++-- server/timer.c | 1 + server/token.c | 3 +- server/trace.c | 1 + 35 files changed, 186 insertions(+), 46 deletions(-) diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index e680e8c34b0..bf3b6ade560 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -44,7 +44,7 @@ extern void dump_ObjectAttributes (const OBJECT_ATTRIBUTES *ObjectAttributes); extern void NTDLL_get_server_timeout( abs_time_t *when, const LARGE_INTEGER *timeout ); extern void NTDLL_from_server_timeout( LARGE_INTEGER *timeout, const abs_time_t *when ); extern NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UINT flags, - const LARGE_INTEGER *timeout ); + const LARGE_INTEGER *timeout, HANDLE signal_object ); /* init routines */ extern BOOL SIGNAL_Init(void); diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index dd903cb610e..5fb6cb243b3 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -1156,7 +1156,7 @@ static HANDLER_DEF(usr1_handler) init_handler( HANDLER_CONTEXT ); /* wait with 0 timeout, will only return once the thread is no longer suspended */ timeout.QuadPart = 0; - NTDLL_wait_for_multiple_objects( 0, NULL, 0, &timeout ); + NTDLL_wait_for_multiple_objects( 0, NULL, 0, &timeout, 0 ); } diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 2e97b35912d..87e2abb5d53 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -701,7 +701,7 @@ static void call_apcs( BOOL alertable ) * Implementation of NtWaitForMultipleObjects */ NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UINT flags, - const LARGE_INTEGER *timeout ) + const LARGE_INTEGER *timeout, HANDLE signal_object ) { NTSTATUS ret; int cookie; @@ -713,6 +713,7 @@ NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UIN { req->flags = flags; req->cookie = &cookie; + req->signal = signal_object; NTDLL_get_server_timeout( &req->timeout, timeout ); wine_server_add_data( req, handles, count * sizeof(HANDLE) ); ret = wine_server_call( req ); @@ -722,6 +723,7 @@ NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UIN if (ret != STATUS_USER_APC) break; call_apcs( (flags & SELECT_ALERTABLE) != 0 ); if (flags & SELECT_ALERTABLE) break; + signal_object = 0; /* don't signal it multiple times */ } /* A test on Windows 2000 shows that Windows always yields during @@ -748,7 +750,7 @@ NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, if (wait_all) flags |= SELECT_ALL; if (alertable) flags |= SELECT_ALERTABLE; - return NTDLL_wait_for_multiple_objects( count, handles, flags, timeout ); + return NTDLL_wait_for_multiple_objects( count, handles, flags, timeout, 0 ); } @@ -761,6 +763,20 @@ NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, const LA } +/****************************************************************** + * NtSignalAndWaitForSingleObject (NTDLL.@) + */ +NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE hSignalObject, HANDLE hWaitObject, + BOOLEAN alertable, const LARGE_INTEGER *timeout ) +{ + UINT flags = SELECT_INTERRUPTIBLE; + + if (!hSignalObject) return STATUS_INVALID_HANDLE; + if (alertable) flags |= SELECT_ALERTABLE; + return NTDLL_wait_for_multiple_objects( 1, &hWaitObject, flags, timeout, hSignalObject ); +} + + /****************************************************************** * NtYieldExecution (NTDLL.@) */ @@ -785,7 +801,7 @@ NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeou { UINT flags = SELECT_INTERRUPTIBLE; if (alertable) flags |= SELECT_ALERTABLE; - return NTDLL_wait_for_multiple_objects( 0, NULL, flags, timeout ); + return NTDLL_wait_for_multiple_objects( 0, NULL, flags, timeout, 0 ); } if (!timeout) /* sleep forever */ @@ -819,14 +835,3 @@ NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeou } return STATUS_SUCCESS; } - - -/****************************************************************** - * NtSignalAndWaitForSingleObject (NTDLL.@) - */ -NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE hSignalObject, HANDLE hWaitObject, - BOOLEAN bAlertable, PLARGE_INTEGER Timeout ) -{ - FIXME("%p %p %d %p\n", hSignalObject, hWaitObject, bAlertable, Timeout); - return STATUS_SUCCESS; -} diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index eb415561c9a..fd3f6401c7d 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -603,6 +603,7 @@ struct select_request struct request_header __header; int flags; void* cookie; + obj_handle_t signal; abs_time_t timeout; /* VARARG(handles,handles); */ }; @@ -3902,6 +3903,6 @@ union generic_reply struct set_mailslot_info_reply set_mailslot_info_reply; }; -#define SERVER_PROTOCOL_VERSION 170 +#define SERVER_PROTOCOL_VERSION 171 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/include/winternl.h b/include/winternl.h index 23cd84927e1..09524673ea1 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -1521,7 +1521,7 @@ NTSTATUS WINAPI NtSetSecurityObject(HANDLE,SECURITY_INFORMATION,PSECURITY_DESCR NTSTATUS WINAPI NtSetSystemTime(const LARGE_INTEGER*,LARGE_INTEGER*); NTSTATUS WINAPI NtSetTimer(HANDLE, const LARGE_INTEGER*, PTIMERAPCROUTINE, PVOID, BOOLEAN, ULONG, BOOLEAN*); NTSTATUS WINAPI NtSetValueKey(HKEY,const UNICODE_STRING *,ULONG,ULONG,const void *,ULONG); -NTSTATUS WINAPI NtSignalAndWaitForSingleObject(HANDLE,HANDLE,BOOLEAN,PLARGE_INTEGER); +NTSTATUS WINAPI NtSignalAndWaitForSingleObject(HANDLE,HANDLE,BOOLEAN,const LARGE_INTEGER*); NTSTATUS WINAPI NtSuspendThread(HANDLE,PULONG); NTSTATUS WINAPI NtTerminateProcess(HANDLE,LONG); NTSTATUS WINAPI NtTerminateThread(HANDLE,LONG); diff --git a/server/atom.c b/server/atom.c index e14c05eff2b..341cf6b8c17 100644 --- a/server/atom.c +++ b/server/atom.c @@ -70,7 +70,8 @@ static const struct object_ops atom_table_ops = 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 2d426443794..51867dd7ab9 100644 --- a/server/change.c +++ b/server/change.c @@ -71,6 +71,7 @@ static const struct object_ops change_ops = 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 b51f56de2b8..a513538615c 100644 --- a/server/console.c +++ b/server/console.c @@ -46,6 +46,7 @@ static const struct object_ops console_input_ops = NULL, /* remove_queue */ NULL, /* signaled */ no_satisfied, /* satisfied */ + no_signal, /* signal */ no_get_fd, /* get_fd */ console_input_destroy /* destroy */ }; @@ -70,6 +71,7 @@ static const struct object_ops console_input_events_ops = 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 @@ static const struct object_ops screen_buffer_ops = 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 bde88a2ea4f..b1ba9b15c49 100644 --- a/server/debugger.c +++ b/server/debugger.c @@ -72,6 +72,7 @@ static const struct object_ops debug_event_ops = 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 @@ static const struct object_ops debug_ctx_ops = 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 e1487d3062c..fa1dbbfba2c 100644 --- a/server/event.c +++ b/server/event.c @@ -41,6 +41,7 @@ struct event 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 @@ static const struct object_ops event_ops = 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 @@ static int event_satisfied( struct object *obj, struct thread *thread ) 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 ef5b31cf413..72c3d9faa7c 100644 --- a/server/fd.c +++ b/server/fd.c @@ -159,6 +159,7 @@ static const struct object_ops fd_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* satisfied */ + no_signal, /* signal */ no_get_fd, /* get_fd */ fd_destroy /* destroy */ }; @@ -188,6 +189,7 @@ static const struct object_ops inode_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* satisfied */ + no_signal, /* signal */ no_get_fd, /* get_fd */ inode_destroy /* destroy */ }; @@ -218,6 +220,7 @@ static const struct object_ops file_lock_ops = 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 d28dc0d42d0..45f2bc0a8a6 100644 --- a/server/file.c +++ b/server/file.c @@ -83,6 +83,7 @@ static const struct object_ops file_ops = 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 ae68a7a4ef4..347960dd06e 100644 --- a/server/handle.c +++ b/server/handle.c @@ -106,6 +106,7 @@ static const struct object_ops handle_table_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* satisfied */ + no_signal, /* signal */ no_get_fd, /* get_fd */ handle_table_destroy /* destroy */ }; @@ -385,6 +386,16 @@ struct object *get_handle_obj( struct process *process, obj_handle_t handle, 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 91b7a2cbe5d..84faae1e517 100644 --- a/server/handle.h +++ b/server/handle.h @@ -38,6 +38,7 @@ extern obj_handle_t alloc_handle( struct process *process, void *obj, 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 293b20c5dd2..c228f987deb 100644 --- a/server/hook.c +++ b/server/hook.c @@ -77,6 +77,7 @@ static const struct object_ops hook_table_ops = 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 7a6230f2e6d..4066e57e817 100644 --- a/server/mailslot.c +++ b/server/mailslot.c @@ -72,6 +72,7 @@ static const struct object_ops mailslot_ops = 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 @@ static const struct object_ops mail_writer_ops = 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 8992986f081..046bc0b86a6 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -62,6 +62,7 @@ static const struct object_ops mapping_ops = 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 1b1ef37b21e..c1b59bb85bd 100644 --- a/server/mutex.c +++ b/server/mutex.c @@ -44,6 +44,7 @@ static void mutex_dump( struct object *obj, int verbose ); 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 @@ static const struct object_ops mutex_ops = 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 @@ static int mutex_satisfied( struct object *obj, struct thread *thread ) 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 dd1d3dda91c..b5077be1691 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -106,6 +106,7 @@ static const struct object_ops named_pipe_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* satisfied */ + no_signal, /* signal */ no_get_fd, /* get_fd */ named_pipe_destroy /* destroy */ }; @@ -128,6 +129,7 @@ static const struct object_ops pipe_server_ops = 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 @@ static const struct object_ops pipe_client_ops = 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 91959b65c5a..479b09c646a 100644 --- a/server/object.c +++ b/server/object.c @@ -273,6 +273,12 @@ int no_satisfied( struct object *obj, struct thread *thread ) 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 44dfe18b93b..e8865263128 100644 --- a/server/object.h +++ b/server/object.h @@ -59,6 +59,8 @@ struct object_ops 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 void release_object( void *obj ); 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 12f9a1e1191..d2f8c89e857 100644 --- a/server/process.c +++ b/server/process.c @@ -70,6 +70,7 @@ static const struct object_ops process_ops = 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 @@ static const struct object_ops startup_info_ops = 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 3427fd070c0..fe892184ea2 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -480,6 +480,7 @@ enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC_IO }; @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 e801fb05d70..c2fb9a9c667 100644 --- a/server/queue.c +++ b/server/queue.c @@ -146,6 +146,7 @@ static const struct object_ops msg_queue_ops = 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 @@ static const struct object_ops thread_input_ops = 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 6f85f5721cf..c7dcd73cab4 100644 --- a/server/registry.c +++ b/server/registry.c @@ -138,6 +138,7 @@ static const struct object_ops key_ops = 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 4f943d0b857..8d33660bf66 100644 --- a/server/request.c +++ b/server/request.c @@ -93,6 +93,7 @@ static const struct object_ops master_socket_ops = 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 27aba0d6f7b..7886842cf07 100644 --- a/server/semaphore.c +++ b/server/semaphore.c @@ -41,6 +41,7 @@ struct semaphore 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 @@ static const struct object_ops semaphore_ops = 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 @@ static struct semaphore *create_semaphore( const WCHAR *name, size_t len, 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; + } + 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 prev; + return 1; } static void semaphore_dump( struct object *obj, int verbose ) @@ -130,6 +126,19 @@ static int semaphore_satisfied( struct object *obj, struct thread *thread ) 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 @@ DECL_HANDLER(open_semaphore) /* 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 6f90f5f3a3e..014142e190e 100644 --- a/server/serial.c +++ b/server/serial.c @@ -101,6 +101,7 @@ static const struct object_ops serial_ops = 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 ea1c15b8627..470a476de9d 100644 --- a/server/signal.c +++ b/server/signal.c @@ -62,6 +62,7 @@ static const struct object_ops handler_ops = 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 975728a8e31..61265badfe6 100644 --- a/server/snapshot.c +++ b/server/snapshot.c @@ -61,6 +61,7 @@ static const struct object_ops snapshot_ops = 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 f3f27fc6cd7..7fcb406f702 100644 --- a/server/sock.c +++ b/server/sock.c @@ -107,6 +107,7 @@ static const struct object_ops sock_ops = 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 af6657efca2..2d7a61bd08c 100644 --- a/server/thread.c +++ b/server/thread.c @@ -92,6 +92,7 @@ static const struct object_ops thread_ops = 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 @@ static void thread_timeout( void *ptr ) 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 @@ static void select_on( int count, void *cookie, const obj_handle_t *handles, 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(resume_thread) 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 1903ba71fd7..720c6f328cc 100644 --- a/server/timer.c +++ b/server/timer.c @@ -59,6 +59,7 @@ static const struct object_ops timer_ops = 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 23fe27cd852..e30f75525bf 100644 --- a/server/token.c +++ b/server/token.c @@ -79,7 +79,8 @@ static const struct object_ops token_ops = 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 d12c962c040..2de4ddf13ac 100644 --- a/server/trace.c +++ b/server/trace.c @@ -760,6 +760,7 @@ static void dump_select_request( const struct select_request *req ) { 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, "," ); -- GitLab