Here is a patch for posix semaphores. I've made a bunch of corrections
suggested by dw. I've applied the patch to my local mingw-w64 and generated
a new dll and replaced the old one and the example program of libtubo (git
version) works just fine.

 I'll be testing parallel makes next as unnamed semaphores (sem_wait()) is
alsoe in the GNU configure and make sequence. First impression is that
nothing is broken.

License on the code contained in this patch is BSD, which apparently is the
same as that for mingw-64, so use as desired.

Feedback is appreciated.


Index: mingw-w64-libraries/winpthreads/include/semaphore.h
===================================================================
--- mingw-w64-libraries/winpthreads/include/semaphore.h    (revision 6379)
+++ mingw-w64-libraries/winpthreads/include/semaphore.h    (working copy)
@@ -66,7 +66,7 @@
 int WINPTHREAD_SEMA_API sem_post_multiple(sem_t *sem, int count);

 /* yes, it returns a semaphore (or SEM_FAILED) */
-sem_t * WINPTHREAD_SEMA_API sem_open(const char * name, int oflag, mode_t
mode, unsigned int value);
+sem_t * WINPTHREAD_SEMA_API sem_open(const char * name, int oflag, ...);

 int WINPTHREAD_SEMA_API sem_close(sem_t * sem);

Index: mingw-w64-libraries/winpthreads/src/sem.c
===================================================================
--- mingw-w64-libraries/winpthreads/src/sem.c    (revision 6379)
+++ mingw-w64-libraries/winpthreads/src/sem.c    (working copy)
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2011 mingw-w64 project
+   Copyright (c) 2013 mingw-w64 project

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the
"Software"),
@@ -20,331 +20,250 @@
    DEALINGS IN THE SOFTWARE.
 */

-#include <windows.h>
-#include <stdio.h>
-#include <malloc.h>
-#include "pthread.h"
-#include "thread.h"
-#include "misc.h"
-#include "semaphore.h"
-#include "sem.h"
-#include "mutex.h"
-#include "ref.h"
+// Semaphore wrappers: <edscott.wilson.gar...@gmail.com>

-int do_sema_b_wait_intern (HANDLE sema, int nointerrupt, DWORD timeout);

-static int
-sem_result (int res)
-{
-  if (res != 0) {
-    errno = res;
-    return -1;
-  }
-  return 0;
-}
+# include "sem.h"
+# include <conio.h>
+# include <tchar.h>
+# include <stdarg.h>
+# include <sys/types.h>
+# include <sys/time.h>
+# include <fcntl.h>
+# include <limits.h>

-int
-sem_init (sem_t *sem, int pshared, unsigned int value)
-{
-  _sem_t *sv;
+// These macros are for debugging purposes
+// TRACE will display execution flow line
+// DBG will display error messages
+#ifdef DEBUG_TRACE
+# define TRACE(...)   \
+    { \
+    fprintf(stderr, "TRACE: ");\
+    fprintf(stderr, __VA_ARGS__); \
+    fflush(stderr);\
+   }
+#else
+# define TRACE(...)   { (void)0; }
+#endif

-  if (!sem || value > (unsigned int)SEM_VALUE_MAX)
-    return sem_result (EINVAL);
-  if (pshared != PTHREAD_PROCESS_PRIVATE)
-    return sem_result (EPERM);
+#ifdef DEBUG
+# define DBG(...)   \
+    { \
+    fprintf(stderr, "DBG: ");\
+    fprintf(stderr, __VA_ARGS__); \
+    fflush(stderr);\
+   }
+#else
+# define DBG(...)   { (void)0; }
+#endif

-  if (!(sv = (sem_t) calloc (1,sizeof (*sv))))
-    return sem_result (ENOMEM);

-  sv->value = value;
-  if (pthread_mutex_init (&sv->vlock, NULL) != 0)
-    {
-      free (sv);
-      return sem_result (ENOSPC);
-    }
-  if ((sv->s = CreateSemaphore (NULL, 0, SEM_VALUE_MAX, NULL)) == NULL)
-    {
-      pthread_mutex_destroy (&sv->vlock);
-      free (sv);
-      return sem_result (ENOSPC);
-    }

-  sv->valid = LIFE_SEM;
-  *sem = sv;
-  return 0;
-}
+/**
+ * _sem_open:
+ * @name: name of the process shared semaphore. Prefix name with Local/
+ * @mode: not used but must be set to other than zero
+ **/
+sem_t *sem_open(const char *name, int oflag, ...){
+    va_list var_args;
+    int mode;
+    unsigned int value;
+    TRACE("sem_open(%s)\n", name);
+    // sem_open() is for named seamphores, hence:
+    if (!name) goto invalid;

-int
-sem_destroy (sem_t *sem)
-{
-  int r;
-  _sem_t *sv = NULL;
-
-  if (!sem || (sv = *sem) == NULL)
-    return sem_result (EINVAL);
-  if ((r = pthread_mutex_lock (&sv->vlock)) != 0)
-    return sem_result (r);
-
-  if (sv->value < 0)
-    {
-      pthread_mutex_unlock (&sv->vlock);
-      return sem_result (EBUSY);
+    HANDLE handle;
+    if (oflag & O_CREAT) {
+        va_start(var_args, oflag);
+        mode = va_arg(var_args, int);
+    if (!mode) goto invalid;
+        value = va_arg(var_args, unsigned int);
+        if (value > SEM_VALUE_MAX) goto invalid;
+        va_end(var_args);
+        handle = CreateSemaphore(NULL, (LONG) value, (LONG) SEM_VALUE_MAX,
name);
+        int last_error = GetLastError();
+        if ((oflag & O_EXCL) && last_error == ERROR_ALREADY_EXISTS){
+            errno = EEXIST;
+            DBG("sem_open(): %s\n", strerror(EEXIST));
+            CloseHandle(handle);
+            return (sem_t *)SEM_FAILED;
+        }
+    } else {
+        handle = OpenSemaphore( SEMAPHORE_ALL_ACCESS, FALSE, name);
+        if (!handle){
+           DBG("sem_open(): windows error %d\n", GetLastError());
+           return (sem_t *)SEM_FAILED;
+        }
     }
-  if (!CloseHandle (sv->s))
-    {
-      pthread_mutex_unlock (&sv->vlock);
-      return sem_result (EINVAL);
-    }
-  *sem = NULL;
-  sv->value = SEM_VALUE_MAX;
-  pthread_mutex_unlock(&sv->vlock);
-  Sleep (0);
-  while (pthread_mutex_destroy (&sv->vlock) == EBUSY)
-    Sleep (0);
-  sv->valid = DEAD_SEM;
-  free (sv);
-  return 0;
-}

-static int
-sem_std_enter (sem_t *sem,_sem_t **svp, int do_test)
-{
-  int r;
-  _sem_t *sv;
-
-  if (do_test)
-    pthread_testcancel ();
-  if (!sem)
-    return sem_result (EINVAL);
-  sv = *sem;
-  if (sv == NULL)
-    return sem_result (EINVAL);
-
-  if ((r = pthread_mutex_lock (&sv->vlock)) != 0)
-    return sem_result (r);
-
-  if (*sem == NULL)
-    {
-      pthread_mutex_unlock(&sv->vlock);
-      return sem_result (EINVAL);
+    if (handle == NULL){
+        DBG("sem_open() %s semaphore %s failed, windows error %d.\n",
+                (oflag & O_CREAT)?"Create":"Open", name, GetLastError());
+        goto invalid;
     }
-  *svp = sv;
-  return 0;
-}

-int
-sem_trywait (sem_t *sem)
-{
-  _sem_t *sv;
-
-  if (sem_std_enter (sem, &sv, 0) != 0)
-    return -1;
-  if (sv->value <= 0)
-    {
-      pthread_mutex_unlock (&sv->vlock);
-      return sem_result (EAGAIN);
+    _sem_t *_sem = (_sem_t *)malloc(sizeof(_sem_t));
+    if (!_sem) {
+            DBG( "sem_open() malloc(%d): %s\n",
sizeof(_sem_t),strerror(errno));
+            return (sem_t *)SEM_FAILED;
     }
-  sv->value--;
-  pthread_mutex_unlock (&sv->vlock);
-
-  return 0;
+    _sem->handle = handle;
+    _sem->named = 1;
+    TRACE ("sem_open() %s semaphore %s OK!\n",
+                    (oflag & O_CREAT)?"Create":"Open", name,
+                    (intptr_t)handle);
+    return (sem_t *)_sem;
+invalid:
+    errno = EINVAL;
+    DBG("sem_open(): %s\n", strerror(errno));
+    return (sem_t *)SEM_FAILED;
 }

-struct sSemTimedWait
-{
-  sem_t *p;
-  int *ret;
-};

-static void
-clean_wait_sem (void *s)
-{
-  struct sSemTimedWait *p = (struct sSemTimedWait *) s;
-  _sem_t *sv = NULL;
+int sem_init(sem_t *sem, int pshared, unsigned int value){

-  if (sem_std_enter (p->p, &sv, 0) != 0)
-    return;
+    HANDLE handle = CreateSemaphore(NULL, (LONG) value, (LONG)
SEM_VALUE_MAX, NULL);
+    if (handle == NULL) {
+            DBG( "sem_init() CreateSemaphore(), windows error %d\n",
GetLastError());
+            errno = EINVAL;
+            return -1;
+    }
+    TRACE("--> sem_open(unnamed) got %d initialized to %d\n",
(intptr_t)handle, value);

-  if (WaitForSingleObject (sv->s, 0) != WAIT_OBJECT_0)
-    InterlockedIncrement (&sv->value);
-  else if (p->ret)
-    p->ret[0] = 0;
-  pthread_mutex_unlock (&sv->vlock);
+    ((_sem_t *)sem)->handle = handle;
+    ((_sem_t *)sem)->named = 0;
+
+    return 0;
 }

-int
-sem_wait (sem_t *sem)
-{
-  long cur_v;
-  int ret = 0;
-  _sem_t *sv;
-  HANDLE semh;
-  struct sSemTimedWait arg;
+int sem_close(sem_t *sem){
+    TRACE("closing semaphore %d\n", *sem);
+    if (!sem || sem == SEM_FAILED) {
+            DBG( "sem_close(): %s\n", strerror(EINVAL));
+            errno = EBADF;
+            return -1;
+    }

-  if (sem_std_enter (sem, &sv, 1) != 0)
-    return -1;

-  arg.ret = NULL;
-  arg.p = sem;
-  InterlockedDecrement (&sv->value);
-  cur_v = sv->value;
-  semh = sv->s;
-  pthread_mutex_unlock (&sv->vlock);
+    BOOL result = CloseHandle(((_sem_t *)sem)->handle);
+    if (!result){
+        DBG( "sem_close(), windows error %d\n", GetLastError());
+        errno = EINVAL;
+        return -1;
+    }

-  if (cur_v >= 0)
+    // If it is a named semaphore, we free allocated memory.
+    if (((_sem_t *)sem)->named) {
+        TRACE("Free sem %d now\n", ((_sem_t *)sem)->handle);
+        free(sem);
+    } else {
+         TRACE("Will not free sem  %d (unnamed). You should call
sem_destroy() for this semaphore.\n", ((_sem_t *)sem)->handle);
+    }
     return 0;
-  else
-    {
-      pthread_cleanup_push (clean_wait_sem, (void *) &arg);
-      ret = do_sema_b_wait_intern (semh, 2, INFINITE);
-      pthread_cleanup_pop (ret);
-      if (ret == EINVAL)
-        return 0;
-    }
+}

-  if (!ret)
+int sem_unlink(const char *name){
+    // Windows unlinks when no process has the semaphore open.
+    // This behavior is race prone, so beware.
     return 0;
-
-  return sem_result (ret);
 }

-int
-sem_timedwait (sem_t *sem, const struct timespec *t)
-{
-  int cur_v, ret = 0;
-  DWORD dwr;
-  HANDLE semh;
-  _sem_t *sv;
-  struct sSemTimedWait arg;
-
-  if (!t)
-    return sem_wait (sem);
-  dwr = dwMilliSecs(_pthread_rel_time_in_ms (t));
-
-  if (sem_std_enter (sem, &sv, 1) != 0)
-    return -1;
-
-  arg.ret = &ret;
-  arg.p = sem;
-  InterlockedDecrement (&sv->value);
-  cur_v = sv->value;
-  semh = sv->s;
-  pthread_mutex_unlock(&sv->vlock);
-
-  if (cur_v >= 0)
-    return 0;
-  else
-    {
-      pthread_cleanup_push (clean_wait_sem, (void *) &arg);
-      ret = do_sema_b_wait_intern (semh, 2, dwr);
-      pthread_cleanup_pop (ret);
-      if (ret == EINVAL)
-        return 0;
+int sem_destroy(sem_t *sem){
+    if (!sem || ((_sem_t *)sem)->named) {
+            DBG( "sem_destroy(): %s\n", strerror(EINVAL));
+            errno = EINVAL;
+            return -1;
     }
-
-  if (!ret)
+    free(sem);
     return 0;
-  return sem_result (ret);
 }

-int
-sem_post (sem_t *sem)
-{
-  _sem_t *sv;;

-  if (sem_std_enter (sem, &sv, 0) != 0)
-    return -1;
-
-  if (sv->value >= SEM_VALUE_MAX)
-    {
-      pthread_mutex_unlock (&sv->vlock);
-      return sem_result (ERANGE);
-    }
-  InterlockedIncrement (&sv->value);
-  if (sv->value > 0 || ReleaseSemaphore (sv->s, 1, NULL))
-    {
-      pthread_mutex_unlock (&sv->vlock);
-      return 0;
-    }
-  InterlockedDecrement (&sv->value);
-  pthread_mutex_unlock (&sv->vlock);
-
-  return sem_result (EINVAL);
+int sem_post_multiple(sem_t *sem, int count){
+   TRACE("Releasing semaphore %d, %d time%s.\n",
+                   ((_sem_t *)sem)->handle, count, (count > 1)?"s":"");
+   BOOL result = ReleaseSemaphore( ((_sem_t *)sem)->handle, count, NULL);
+   if (!result){
+        DBG( "sem_post_multiple(), windows error %d\n",  GetLastError());
+        return -1;
+   }
+   return 0;
 }

-int
-sem_post_multiple (sem_t *sem, int count)
-{
-  int waiters_count;
-  _sem_t *sv;;
-
-  if (count <= 0)
-    return sem_result (EINVAL);
-  if (sem_std_enter (sem, &sv, 0) != 0)
-    return -1;
-
-  if (sv->value > (SEM_VALUE_MAX - count))
-  {
-    pthread_mutex_unlock (&sv->vlock);
-    return sem_result (ERANGE);
-  }
-  waiters_count = -sv->value;
-  sv->value += count;
-  /*InterlockedExchangeAdd((long*)&sv->value, (long) count);*/
-  if (waiters_count <= 0
-      || ReleaseSemaphore (sv->s,
-               (waiters_count < count ? waiters_count
-                             : count), NULL))
-  {
-    pthread_mutex_unlock(&sv->vlock);
-    return 0;
-  }
-  /*InterlockedExchangeAdd((long*)&sv->value, -((long) count));*/
-  sv->value -= count;
-  pthread_mutex_unlock(&sv->vlock);
-  return sem_result (EINVAL);
+int sem_post(sem_t *sem){
+   return sem_post_multiple(sem, 1);
 }

-sem_t *
-sem_open (const char *name, int oflag, mode_t mode, unsigned int value)
-{
-  sem_result (ENOSYS);
-  return NULL;
+static
+int _sem_timeout(_sem_t *_sem, time_t timeout){
+   TRACE("Wait on semaphore %d\n", _sem->handle);
+   if (!_sem) {
+       errno = EINVAL;
+       return -1;
+   }
+   DWORD result = WaitForSingleObject(_sem->handle, timeout);
+   switch (result){
+      case WAIT_OBJECT_0:
+          TRACE("Wait OK on semaphore %d\n", _sem->handle);
+          return 0;
+      case WAIT_TIMEOUT:
+      errno = ETIMEDOUT;
+          TRACE("Wait timed out on semaphore %d\n", _sem->handle);
+          return -1;
+      case WAIT_FAILED:
+      errno = EINTR;
+          TRACE("Wait failed on semaphore %d\n", _sem->handle);
+          DBG( "sem_timeout(), windows error %d\n",  GetLastError());
+          return -1;
+   }
+   return -1;
 }

-int
-sem_close (sem_t *sem)
-{
-  return sem_result (ENOSYS);
+int sem_trywait(sem_t *sem){
+    if (_sem_timeout(((_sem_t *)sem), 0) < 0){
+        errno = EAGAIN;
+        return -1;
+    }
+    return 0;
 }

-int
-sem_unlink (const char *name)
-{
-  return sem_result (ENOSYS);
+int sem_wait(sem_t *sem){
+    return _sem_timeout(((_sem_t *)sem), INFINITE);
 }
+// Note: sem_timedwait is only accurate to the nearest microsecond.
+int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout){
+    struct timeval tv;
+    if (gettimeofday(&tv, NULL) < 0){
+           DBG( "gettimeofday(): %s\n", strerror(errno));
+           return -1;
+    }
+    // Seconds time difference
+    time_t seconds = abs_timeout->tv_sec - tv.tv_sec;
+    if (seconds >= 0){
+    // round off nanoseconds to nearest microsecond
+        time_t useconds = (abs_timeout->tv_nsec + 500) / 1000;
+    // Microsecond time difference (may be negative)
+    useconds -= tv.tv_usec;
+    // Total microsecond difference
+    useconds += (seconds * 1000);
+    if (useconds >= 0) {
+            return _sem_timeout(((_sem_t *)sem), useconds);
+    }
+    }
+    // Timeout has expired.
+    if (sem_trywait(sem) < 0){
+        // Cannot immediately decrease semaphore
+        errno = EAGAIN;
+        return -1;
+    }
+    // Semaphore immediately decreased.
+    return 0;
+}

-int
-sem_getvalue (sem_t *sem, int *sval)
-{
-  _sem_t *sv;
-  int r;

-  if (!sval)
-    return sem_result (EINVAL);
-
-  if (!sem || (sv = *sem) == NULL)
-    return sem_result (EINVAL);
-
-  if ((r = pthread_mutex_lock (&sv->vlock)) != 0)
-    return sem_result (r);
-  if (*sem == NULL)
-    {
-      pthread_mutex_unlock (&sv->vlock);
-      return sem_result (EINVAL);
-    }
-
-  *sval = (int) sv->value;
-  pthread_mutex_unlock (&sv->vlock);
-  return 0;
+// Note: Seems this can't be implemented in Windows.
+int sem_getvalue(sem_t * sem, int * sval){
+    errno = EINVAL;
+    DBG( "sem_getvalue(): %s\n", strerror(errno));
+    return -1;
 }
Index: mingw-w64-libraries/winpthreads/src/sem.h
===================================================================
--- mingw-w64-libraries/winpthreads/src/sem.h    (revision 6379)
+++ mingw-w64-libraries/winpthreads/src/sem.h    (working copy)
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2011 mingw-w64 project
+   Copyright (c) 2013 mingw-w64 project

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the
"Software"),
@@ -22,20 +22,55 @@

 #ifndef WIN_SEM
 #define WIN_SEM
+# define  _WIN32_WINNT 0x502

-#include <windows.h>
-#include "mutex.h"
+# include <windows.h>
+# include <sys/stat.h>
+# include <sys/time.h>
+# include <stdio.h>
+# include <errno.h>
+# include <semaphore.h>

-#define LIFE_SEM 0xBAB1F00D
-#define DEAD_SEM 0xDEADBEEF
+#ifdef __cplusplus
+extern "C" {
+#endif

-typedef struct _sem_t _sem_t;
-struct _sem_t
-{
-    unsigned int valid;
-    HANDLE s;
-    volatile long value;
-    pthread_mutex_t vlock;
+#ifndef SEM_FAILED
+#define SEM_FAILED NULL
+#endif
+#ifndef SEM_VALUE_MAX
+#define SEM_VALUE_MAX INT_MAX
+#endif
+
+#ifndef ETIMEDOUT
+#define ETIMEDOUT 138
+#endif
+
+#ifndef _TIMESPEC_DEFINED
+#define _TIMESPEC_DEFINED
+struct timespec {
+  time_t  tv_sec;   /* Seconds */
+  long    tv_nsec;  /* Nanoseconds */
 };

-#endif /* WIN_SEM */
\ No newline at end of file
+struct itimerspec {
+  struct timespec  it_interval;  /* Timer period */
+  struct timespec  it_value;     /* Timer expiration */
+};
+#endif
+
+typedef struct _sem_t {
+   HANDLE handle;
+   BOOL named;
+} _sem_t;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WIN_SEM */
+
+
+
+



-- 
------------------------------------------------------------------------------------
Dr. Edscott Wilson Garcia
Applied Mathematics and Computing
Mexican Petroleum Institute
------------------------------------------------------------------------------
Shape the Mobile Experience: Free Subscription
Software experts and developers: Be at the forefront of tech innovation.
Intel(R) Software Adrenaline delivers strategic insight and game-changing 
conversations that shape the rapidly evolving mobile landscape. Sign up now. 
http://pubads.g.doubleclick.net/gampad/clk?id=63431311&iu=/4140/ostg.clktrk
_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to