When a semaphore is opened or created, the client process now also opens that semaphore and can perform operations on it --- dlls/ntdll/sync.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+)
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 6892732..f4ac276 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -48,6 +48,19 @@ #include <stdlib.h> #include <time.h>
+#ifdef ENABLE_HYBRID_SYNC +# ifdef HAVE_SEMAPHORE_H +# include <semaphore.h> +# endif +# include <fcntl.h> +# include <sys/stat.h> +# include <semaphore.h> +# include <errno.h> +# ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +# endif +#endif + #include "ntstatus.h" #define WIN32_NO_STATUS #define NONAMELESSUNION @@ -58,9 +71,234 @@ #include "ntdll_misc.h"
WINE_DEFAULT_DEBUG_CHANNEL(ntdll); +WINE_DECLARE_DEBUG_CHANNEL(ntdllsync);
HANDLE keyed_event = NULL;
+static NTSTATUS semaphore_add(const HANDLE h, LONG MaximumCount, unsigned int key, unsigned long debug_server_ptr); + +#ifndef ENABLE_HYBRID_SYNC +static NTSTATUS semaphore_add(const HANDLE h, LONG MaximumCount, unsigned int key, unsigned long debug_server_ptr) +{ + return STATUS_SUCCESS; +} + +static inline NTSTATUS semaphore_up(const HANDLE h, ULONG count, PULONG previous) +{ + return STATUS_NOT_IMPLEMENTED; +} +#else /* ENABLE_HYBRID_SYNC */ + +struct ntdll_semaphore { + struct ntdll_object obj; + sem_t *p; + LONG max; + unsigned int key; + unsigned long server_ptr; +}; + +static void semaphore_dump(const struct ntdll_object *obj, char **start, const char *const end); + +static int semaphore_get_value(struct ntdll_semaphore *sem) +{ + int ret; + if (sem_getvalue(sem->p, &ret) == -1) + { + perror("sem_getvalue"); + /* XXX: is there already a thread safe mechanism for errno descriptions? */ + ERR_(ntdllsync)("sem_getvalue failed with %08x (%s).\n", errno, strerror(errno)); + assert(0); + + return -1; + } + + return ret; +} + +static NTSTATUS semaphore_up(struct ntdll_semaphore *sem, ULONG count, PULONG previous) +{ + int current_value; + + TRACE_(ntdllsync)("(sem = %s, count = %u, previous = %p)\n", + ntdll_object_dump(&sem->obj), count, previous); + + if ((current_value = semaphore_get_value(sem)) == -1) + return STATUS_INVALID_HANDLE; /* ?? */ + + assert(current_value >= 0); + + if (previous) + *previous = (ULONG)current_value; + + if (current_value + count > sem->max) + return STATUS_SEMAPHORE_LIMIT_EXCEEDED; + + while (count--) + { + /* BUG by multiple threads releasing at the same time, it is possible to exceed sem->max here */ + if (sem_post(sem->p) == -1) + { + perror("sem_post"); + assert(0); + exit(1); + /* ?? */ + } + } + TRACE_(ntdllsync)("success\n"); + + ntdll_server_notify_lock_release(); + return STATUS_SUCCESS; +} + +/* client-side waiting not yet implemented */ +static NTSTATUS semaphore_wait(struct ntdll_object *obj, const LARGE_INTEGER *timeout) +{ + TRACE_(ntdllsync)("(obj = %s, timeout = %p)\n", ntdll_object_dump(obj), timeout); + + return STATUS_NOT_IMPLEMENTED; +} + +/* */ +static BOOL semaphore_signaled(struct ntdll_object *obj) +{ + TRACE_(ntdllsync)("(obj = %s)\n", ntdll_object_dump(obj)); + + return semaphore_get_value((void *)obj) > 0; +} + +static NTSTATUS semaphore_trywait(struct ntdll_object *obj) +{ + struct ntdll_semaphore *sem = (void *)obj; + + TRACE_(ntdllsync)("(obj = %s)\n", ntdll_object_dump(obj)); + + assert(sem->obj.type_id == NTDLL_OBJ_TYPE_SEMAPHORE); + assert(sem->p); + + if (sem_trywait(sem->p)) + { + switch (errno) { + case EAGAIN: + return STATUS_WAS_LOCKED; + case EDEADLK: + return STATUS_POSSIBLE_DEADLOCK; + default: + perror("sem_trywait"); + exit(1); + } + } + return STATUS_SUCCESS; +} + +static NTSTATUS semaphore_trywait_undo(struct ntdll_object *obj) +{ + struct ntdll_semaphore *sem = (void *)obj; + + TRACE_(ntdllsync)("(obj = %s)\n", ntdll_object_dump(obj)); + + assert(sem->obj.type_id == NTDLL_OBJ_TYPE_SEMAPHORE); + assert(sem->p); + + if (sem_post(sem->p) == -1) + { + perror("sem_post"); + exit(1); + } + return STATUS_SUCCESS; +} + +static void semaphore_close(struct ntdll_object *obj) +{ + struct ntdll_semaphore *sem = (void *)obj; + + TRACE_(ntdllsync)("(obj = %s)\n", ntdll_object_dump(obj)); + + assert(sem->obj.type_id == NTDLL_OBJ_TYPE_SEMAPHORE); + assert(sem->p); + + if (sem->p) + sem_close(sem->p); +} + +static void semaphore_dump(const struct ntdll_object *obj, char **start, const char *const end) +{ + struct ntdll_semaphore *sem = (void *)obj; + int count; + int sem_value; + + assert(sem); + assert(sem->p); + assert(sem->obj.type_id == NTDLL_OBJ_TYPE_SEMAPHORE); + + count = snprintf(*start, end - *start, "%p {obj = ", obj); + if (count < 0) + { + perror("snprintf"); + return; + } + *start += count; + + ntdll_object_dump_base(obj, start, end); + + if (sem_getvalue(sem->p, &sem_value) == -1) + sem_value = -1; + + count = snprintf(*start, end - *start, + ", p = %p {value = %d}, max = %d, key = %08x, server_ptr = %p", + sem->p, sem_value, sem->max, sem->key, (void*)sem->server_ptr); + if (count < 0) + perror("snprintf"); +} + +static struct ntdll_object_ops semaphore_ops = { + semaphore_wait, /* wait */ + semaphore_signaled, /* signaled */ + semaphore_trywait, /* trywait */ + semaphore_trywait_undo, /* trywait_undo */ + semaphore_close, /* close */ + semaphore_dump /* dump */ +}; + +static NTSTATUS semaphore_add(const HANDLE h, LONG MaximumCount, unsigned int key, unsigned long server_ptr) +{ + struct ntdll_semaphore *sem; + sem_t *sem_obj; + char name[32]; + + snprintf(name, sizeof(name) - 1, "/wine-sem-%08x", key); + TRACE_(ntdllsync)("(h = %p, MaximumCount = %d, key = %08x, name = "%s")\n", h, MaximumCount, key, name); + sem_obj = sem_open(name, 0); + + if (sem_obj == SEM_FAILED) + { + perror("sem_open"); + assert(0); + exit(1); + } + + sem = (void *)ntdll_object_new(h, sizeof(struct ntdll_semaphore), NTDLL_OBJ_TYPE_SEMAPHORE, &semaphore_ops); + + if (!sem) + { + ERR_(ntdllsync)("ntdll_object_new failed\n"); + sem_close(sem_obj); + return STATUS_NO_MEMORY; + } + sem->max = MaximumCount; + sem->p = sem_obj; + sem->key = key; + sem->server_ptr = server_ptr; + TRACE_(ntdllsync)("%s\n", ntdll_object_dump(&sem->obj)); + + ntdll_handle_add(&sem->obj); + ntdll_object_release(&sem->obj); + + return STATUS_SUCCESS; +} + +#endif /* ENABLE_HYBRID_SYNC */ + + static inline int interlocked_dec_if_nonzero( int *dest ) { int val, tmp; @@ -184,6 +422,7 @@ NTSTATUS WINAPI NtCreateSemaphore( OUT PHANDLE SemaphoreHandle, if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len ); ret = wine_server_call( req ); *SemaphoreHandle = wine_server_ptr_handle( reply->handle ); + semaphore_add(*SemaphoreHandle, MaximumCount, reply->key, (unsigned long)reply->server_ptr); } SERVER_END_REQ;
@@ -212,6 +451,7 @@ NTSTATUS WINAPI NtOpenSemaphore( OUT PHANDLE SemaphoreHandle, if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len ); ret = wine_server_call( req ); *SemaphoreHandle = wine_server_ptr_handle( reply->handle ); + semaphore_add(*SemaphoreHandle, reply->max, reply->key, (unsigned long)reply->server_ptr); } SERVER_END_REQ; return ret;