MIPS: Throw OverflowException if Int32.MinValue is divided by -1
[mono.git] / mono / utils / mono-semaphore.c
index 7363a7f78c2e8f6fda54d5f6b872846bed4b6e2c..55386ae557478a018b9b8dbd4a51d3f47124a862 100644 (file)
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 
-#if (defined(HAVE_SEMAPHORE_H) || defined(USE_MACH_SEMA)) && !defined(__OpenBSD__)
+#if (defined(HAVE_SEMAPHORE_H) || defined(USE_MACH_SEMA))
 /* sem_* or semaphore_* functions in use */
 #  ifdef USE_MACH_SEMA
 #    define TIMESPEC mach_timespec_t
 #    define WAIT_BLOCK(a,b) semaphore_timedwait (*(a), *(b))
+#  elif defined(__OpenBSD__)
+#    define TIMESPEC struct timespec
+#    define WAIT_BLOCK(a) sem_trywait(a)
 #  else
 #    define TIMESPEC struct timespec
 #    define WAIT_BLOCK(a,b) sem_timedwait (a, b)
 #  endif
 
+#define NSEC_PER_SEC 1000000000
 int
-mono_sem_timedwait (MonoSemType *sem, guint32 timeout_ms)
+mono_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, gboolean alertable)
 {
        TIMESPEC ts, copy;
        struct timeval t;
-       int res;
+       int res = 0;
+#if defined(__OpenBSD__)
+       int timeout;
+#endif
 
 #ifndef USE_MACH_SEMA
        if (timeout_ms == 0)
-               return (!sem_trywait (sem));
+               return sem_trywait (sem);
 #endif
        if (timeout_ms == (guint32) 0xFFFFFFFF)
-               return mono_sem_wait (sem);
+               return mono_sem_wait (sem, alertable);
 
+#ifdef USE_MACH_SEMA
+       memset (&t, 0, sizeof (TIMESPEC));
+#else
        gettimeofday (&t, NULL);
+#endif
        ts.tv_sec = timeout_ms / 1000 + t.tv_sec;
        ts.tv_nsec = (timeout_ms % 1000) * 1000000 + t.tv_usec * 1000;
-       while (ts.tv_nsec > 1000000000) {
-               ts.tv_nsec -= 1000000000;
+       while (ts.tv_nsec > NSEC_PER_SEC) {
+               ts.tv_nsec -= NSEC_PER_SEC;
                ts.tv_sec++;
        }
+#if defined(__OpenBSD__)
+       timeout = ts.tv_sec;
+       while (timeout) {
+               if ((res = WAIT_BLOCK (sem)) == 0)
+                       return res;
+
+               if (alertable)
+                       return -1;
+
+               usleep (ts.tv_nsec / 1000);
+               timeout--;
+       }
+#else
        copy = ts;
-       while ((res = WAIT_BLOCK (sem, &ts) == -1) && errno == EINTR)
+       while ((res = WAIT_BLOCK (sem, &ts)) == -1 && errno == EINTR) {
+               struct timeval current;
+               if (alertable)
+                       return -1;
+#ifdef USE_MACH_SEMA
+               memset (&current, 0, sizeof (TIMESPEC));
+#else
+               gettimeofday (&current, NULL);
+#endif
                ts = copy;
+               ts.tv_sec -= (current.tv_sec - t.tv_sec);
+               ts.tv_nsec -= (current.tv_usec - t.tv_usec) * 1000;
+               if (ts.tv_nsec < 0) {
+                       if (ts.tv_sec <= 0) {
+                               ts.tv_nsec = 0;
+                       } else {
+                               ts.tv_sec--;
+                               ts.tv_nsec += NSEC_PER_SEC;
+                       }
+               }
+               if (ts.tv_sec < 0) {
+                       ts.tv_sec = 0;
+                       ts.tv_nsec = 0;
+               }
+       }
+#endif
+       /* OSX might return > 0 for error */
+       if (res != 0)
+               res = -1;
        return res;
 }
 
 int
-mono_sem_wait (MonoSemType *sem)
+mono_sem_wait (MonoSemType *sem, gboolean alertable)
 {
        int res;
 #ifndef USE_MACH_SEMA
-       while ((res = sem_wait (sem) == -1) && errno == EINTR);
+       while ((res = sem_wait (sem) == -1) && errno == EINTR)
 #else
-       while ((res = semaphore_wait (*sem) == -1) && errno == EINTR);
+       while ((res = semaphore_wait (*sem) == -1) && errno == EINTR)
 #endif
+       {
+               if (alertable)
+                       return -1;
+       }
+       /* OSX might return > 0 for error */
+       if (res != 0)
+               res = -1;
        return res;
 }
 
@@ -71,6 +132,9 @@ mono_sem_post (MonoSemType *sem)
        while ((res = sem_post (sem) == -1) && errno == EINTR);
 #else
        while ((res = semaphore_signal (*sem) == -1) && errno == EINTR);
+       /* OSX might return > 0 for error */
+       if (res != 0)
+               res = -1;
 #endif
        return res;
 }
@@ -78,20 +142,29 @@ mono_sem_post (MonoSemType *sem)
 #else
 /* Windows or io-layer functions in use */
 int
-mono_sem_wait (MonoSemType *sem)
+mono_sem_wait (MonoSemType *sem, gboolean alertable)
 {
-       return mono_sem_timedwait (sem, INFINITE);
+       return mono_sem_timedwait (sem, INFINITE, alertable);
 }
 
 int
-mono_sem_timedwait (MonoSemType *sem, guint32 timeout_ms)
+mono_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, gboolean alertable)
 {
        gboolean res;
 
-       res = WaitForSingleObjectEx (*sem, timeout_ms, FALSE);
-       if (!res)
+       while (res = WaitForSingleObjectEx (*sem, timeout_ms, alertable) == WAIT_IO_COMPLETION) {
+               if (alertable) {
+                       errno = EINTR;
+                       return -1;
+               }
+       }
+       switch (res) {
+       case WAIT_OBJECT_0:
+               return 0;    
+       // WAIT_TIMEOUT and WAIT_FAILED
+       default:
                return -1;
-       return 0;
+       }
 }
 
 int