[PATCH 5/8] ntdll: Add posix semaphore management code
Daniel Santos
daniel.santos at pobox.com
Thu Sep 10 01:34:23 CDT 2015
When a semaphore is opened or created, the client process now also opens
that semaphore and can perform operations on it
Signed-off-by: Daniel Santos <daniel.santos at pobox.com>
---
dlls/ntdll/sync.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 232 insertions(+)
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 6892732..84a3ab6 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -48,6 +48,19 @@
#include <stdlib.h>
#include <time.h>
+#if ENABLE_POSIX_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,226 @@
#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);
+
+#if !(ENABLE_POSIX_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_POSIX_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);
+
+#if 0
+static int sem_
+sem_getvalue
+ if (sem_getvalue(sem->p, &ret) == -1)
+ {
+ perror("sem_getvalue");
+ exit(1);
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ return (unsigned int)ret;
+}
+#endif
+
+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 (sem_getvalue(sem->p, ¤t_value) == -1)
+ {
+ perror("sem_getvalue");
+ assert(0);
+ ERR_(ntdllsync)("sem_getvalue failed.\n");
+
+ return STATUS_INVALID_HANDLE; /* ?? */
+ }
+
+ if (previous)
+ *previous = 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");
+ /* ?? */
+ }
+ }
+ 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 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_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_POSIX_SYNC */
+
+
static inline int interlocked_dec_if_nonzero( int *dest )
{
int val, tmp;
@@ -184,6 +414,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 +443,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;
--
2.4.6
More information about the wine-devel
mailing list