2010-04-08 Gonzalo Paniagua Javier <gonzalo@novell.com>
[mono.git] / mono / utils / mono-semaphore.c
1 /*
2  * mono-semaphore.c: mono-semaphore functions
3  *
4  * Author:
5  *      Gonzalo Paniagua Javier  <gonzalo@novell.com>
6  *
7  * (C) 2010 Novell, Inc.
8  */
9
10 #include <config.h>
11 #include <errno.h>
12 #include "utils/mono-semaphore.h"
13 #ifdef HAVE_SYS_TIME_H
14 #include <sys/time.h>
15 #endif
16 #ifdef HAVE_UNISTD_H
17 #include <unistd.h>
18 #endif
19
20 #if (defined(HAVE_SEMAPHORE_H) || defined(USE_MACH_SEMA))
21 /* sem_* or semaphore_* functions in use */
22 #  ifdef USE_MACH_SEMA
23 #    define TIMESPEC mach_timespec_t
24 #    define WAIT_BLOCK(a,b) semaphore_timedwait (*(a), *(b))
25 #  elif defined(__OpenBSD__)
26 #    define TIMESPEC struct timespec
27 #    define WAIT_BLOCK(a) sem_trywait(a)
28 #  else
29 #    define TIMESPEC struct timespec
30 #    define WAIT_BLOCK(a,b) sem_timedwait (a, b)
31 #  endif
32
33 int
34 mono_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, gboolean alertable)
35 {
36         TIMESPEC ts, copy;
37         struct timeval t;
38         int res = 0;
39 #if defined(__OpenBSD__)
40         int timeout;
41 #endif
42
43 #ifndef USE_MACH_SEMA
44         if (timeout_ms == 0)
45                 return (!sem_trywait (sem));
46 #endif
47         if (timeout_ms == (guint32) 0xFFFFFFFF)
48                 return mono_sem_wait (sem, alertable);
49
50         gettimeofday (&t, NULL);
51         ts.tv_sec = timeout_ms / 1000 + t.tv_sec;
52         ts.tv_nsec = (timeout_ms % 1000) * 1000000 + t.tv_usec * 1000;
53         while (ts.tv_nsec > 1000000000) {
54                 ts.tv_nsec -= 1000000000;
55                 ts.tv_sec++;
56         }
57 #if defined(__OpenBSD__)
58         timeout = ts.tv_sec;
59         while (timeout) {
60                 if ((res = WAIT_BLOCK (sem)) == 0)
61                         return res;
62
63                 if (alertable)
64                         return -1;
65
66                 usleep (ts.tv_nsec / 1000);
67                 timeout--;
68         }
69 #else
70         copy = ts;
71         while ((res = WAIT_BLOCK (sem, &ts) == -1) && errno == EINTR) {
72                 if (alertable)
73                         return -1;
74                 ts = copy;
75         }
76 #endif
77         return res;
78 }
79
80 int
81 mono_sem_wait (MonoSemType *sem, gboolean alertable)
82 {
83         int res;
84 #ifndef USE_MACH_SEMA
85         while ((res = sem_wait (sem) == -1) && errno == EINTR)
86 #else
87         while ((res = semaphore_wait (*sem) == -1) && errno == EINTR)
88 #endif
89         {
90                 if (alertable)
91                         return -1;
92         }
93         return res;
94 }
95
96 int
97 mono_sem_post (MonoSemType *sem)
98 {
99         int res;
100 #ifndef USE_MACH_SEMA
101         while ((res = sem_post (sem) == -1) && errno == EINTR);
102 #else
103         while ((res = semaphore_signal (*sem) == -1) && errno == EINTR);
104 #endif
105         return res;
106 }
107
108 #else
109 /* Windows or io-layer functions in use */
110 int
111 mono_sem_wait (MonoSemType *sem, gboolean alertable)
112 {
113         return mono_sem_timedwait (sem, INFINITE, alertable);
114 }
115
116 int
117 mono_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, gboolean alertable)
118 {
119         gboolean res;
120
121         res = WaitForSingleObjectEx (*sem, timeout_ms, alertable);
122         switch (res) {
123         case WAIT_OBJECT_0:
124                 return 0;
125         case WAIT_IO_COMPLETION:
126                 errno = EINTR;
127                 return -1;            
128         // WAIT_TIMEOUT and WAIT_FAILED
129         default:
130                 return -1;
131         }
132 }
133
134 int
135 mono_sem_post (MonoSemType *sem)
136 {
137         if (!ReleaseSemaphore (*sem, 1, NULL))
138                 return -1;
139         return 0;
140 }
141 #endif
142