[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, &current_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