[tests] Remove double inclusion of source file
[mono.git] / mono / utils / mono-os-semaphore.h
1 /*
2  * mono-os-semaphore.h:  Definitions for generic semaphore usage
3  *
4  * Author:
5  *      Geoff Norton  <gnorton@novell.com>
6  *
7  * (C) 2009 Novell, Inc.
8  */
9
10 #ifndef _MONO_SEMAPHORE_H_
11 #define _MONO_SEMAPHORE_H_
12
13 #include <config.h>
14 #include <glib.h>
15
16 #include <errno.h>
17
18 #ifdef HAVE_SYS_TIME_H
19 #include <sys/time.h>
20 #endif
21
22 #ifdef HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif
25
26 #if defined(USE_MACH_SEMA)
27 #include <mach/mach_init.h>
28 #include <mach/task.h>
29 #include <mach/semaphore.h>
30 #elif !defined(HOST_WIN32) && defined(HAVE_SEMAPHORE_H)
31 #include <semaphore.h>
32 #else
33 #include <winsock2.h>
34 #include <windows.h>
35 #endif
36
37 #define MONO_HAS_SEMAPHORES 1
38
39 #ifndef NSEC_PER_SEC
40 #define NSEC_PER_SEC (1000 * 1000 * 1000)
41 #endif
42
43 G_BEGIN_DECLS
44
45 typedef enum {
46         MONO_SEM_FLAGS_NONE      = 0,
47         MONO_SEM_FLAGS_ALERTABLE = 1 << 0,
48 } MonoSemFlags;
49
50 #if defined(USE_MACH_SEMA)
51
52 typedef semaphore_t MonoSemType;
53
54 static inline int
55 mono_os_sem_init (MonoSemType *sem, int value)
56 {
57         return semaphore_create (current_task (), sem, SYNC_POLICY_FIFO, value) != KERN_SUCCESS ? -1 : 0;
58 }
59
60 static inline int
61 mono_os_sem_destroy (MonoSemType *sem)
62 {
63         return semaphore_destroy (current_task (), *sem) != KERN_SUCCESS ? -1 : 0;
64 }
65
66 static inline int
67 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
68 {
69         int res;
70
71 retry:
72         res = semaphore_wait (*sem);
73         g_assert (res != KERN_INVALID_ARGUMENT);
74
75         if (res == KERN_ABORTED && !(flags & MONO_SEM_FLAGS_ALERTABLE))
76                 goto retry;
77
78         return res != KERN_SUCCESS ? -1 : 0;
79 }
80
81 static inline int
82 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
83 {
84         mach_timespec_t ts, copy;
85         struct timeval start, current;
86         int res = 0;
87
88         if (timeout_ms == (guint32) 0xFFFFFFFF)
89                 return mono_os_sem_wait (sem, flags);
90
91         ts.tv_sec = timeout_ms / 1000;
92         ts.tv_nsec = (timeout_ms % 1000) * 1000000;
93         while (ts.tv_nsec >= NSEC_PER_SEC) {
94                 ts.tv_nsec -= NSEC_PER_SEC;
95                 ts.tv_sec++;
96         }
97
98         copy = ts;
99         gettimeofday (&start, NULL);
100
101 retry:
102         res = semaphore_timedwait (*sem, ts);
103         g_assert (res != KERN_INVALID_ARGUMENT);
104
105         if (res == KERN_ABORTED && !(flags & MONO_SEM_FLAGS_ALERTABLE)) {
106                 ts = copy;
107
108                 gettimeofday (&current, NULL);
109                 ts.tv_sec -= (current.tv_sec - start.tv_sec);
110                 ts.tv_nsec -= (current.tv_usec - start.tv_usec) * 1000;
111                 if (ts.tv_nsec < 0) {
112                         if (ts.tv_sec <= 0) {
113                                 ts.tv_nsec = 0;
114                         } else {
115                                 ts.tv_sec--;
116                                 ts.tv_nsec += NSEC_PER_SEC;
117                         }
118                 }
119                 if (ts.tv_sec < 0) {
120                         ts.tv_sec = 0;
121                         ts.tv_nsec = 0;
122                 }
123
124                 goto retry;
125         }
126
127         return res != KERN_SUCCESS ? -1 : 0;
128 }
129
130 static inline int
131 mono_os_sem_post (MonoSemType *sem)
132 {
133         int res;
134 retry:
135         res = semaphore_signal (*sem);
136         g_assert (res != KERN_INVALID_ARGUMENT);
137
138         if (res == KERN_ABORTED)
139                 goto retry;
140
141         return res != KERN_SUCCESS ? -1 : 0;
142 }
143
144 #elif !defined(HOST_WIN32) && defined(HAVE_SEMAPHORE_H)
145
146 typedef sem_t MonoSemType;
147
148 static inline int
149 mono_os_sem_init (MonoSemType *sem, int value)
150 {
151         return sem_init (sem, 0, value);
152 }
153
154 static inline int
155 mono_os_sem_destroy (MonoSemType *sem)
156 {
157         return sem_destroy (sem);
158 }
159
160 static inline int
161 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
162 {
163         int res;
164
165 retry:
166         res = sem_wait (sem);
167         if (res == -1)
168                 g_assert (errno != EINVAL);
169
170         if (res == -1 && errno == EINTR && !(flags & MONO_SEM_FLAGS_ALERTABLE))
171                 goto retry;
172
173         return res != 0 ? -1 : 0;
174 }
175
176 static inline int
177 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
178 {
179         struct timespec ts, copy;
180         struct timeval t;
181         int res = 0;
182
183         if (timeout_ms == 0) {
184                 res = sem_trywait (sem) != 0 ? -1 : 0;
185                 if (res == -1)
186                         g_assert (errno != EINVAL);
187
188                 return res != 0 ? -1 : 0;
189         }
190
191         if (timeout_ms == (guint32) 0xFFFFFFFF)
192                 return mono_os_sem_wait (sem, flags);
193
194         gettimeofday (&t, NULL);
195         ts.tv_sec = timeout_ms / 1000 + t.tv_sec;
196         ts.tv_nsec = (timeout_ms % 1000) * 1000000 + t.tv_usec * 1000;
197         while (ts.tv_nsec >= NSEC_PER_SEC) {
198                 ts.tv_nsec -= NSEC_PER_SEC;
199                 ts.tv_sec++;
200         }
201
202         copy = ts;
203
204 retry:
205 #if defined(__native_client__) && defined(USE_NEWLIB)
206         res = sem_trywait (sem);
207 #else
208         res = sem_timedwait (sem, &ts);
209 #endif
210         if (res == -1)
211                 g_assert (errno != EINVAL);
212
213         if (res == -1 && errno == EINTR && !(flags & MONO_SEM_FLAGS_ALERTABLE)) {
214                 ts = copy;
215                 goto retry;
216         }
217
218         return res != 0 ? -1 : 0;
219 }
220
221 static inline int
222 mono_os_sem_post (MonoSemType *sem)
223 {
224         int res;
225
226         res = sem_post (sem);
227         if (res == -1)
228                 g_assert (errno != EINVAL);
229
230         return res;
231 }
232
233 #else
234
235 typedef HANDLE MonoSemType;
236
237 static inline int
238 mono_os_sem_init (MonoSemType *sem, int value)
239 {
240         *sem = CreateSemaphore (NULL, value, 0x7FFFFFFF, NULL);
241         return *sem == NULL ? -1 : 0;
242 }
243
244 static inline int
245 mono_os_sem_destroy (MonoSemType *sem)
246 {
247         return !CloseHandle (*sem) ? -1 : 0;
248 }
249
250 static inline int
251 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
252 {
253         gboolean res;
254
255 retry:
256         res = WaitForSingleObjectEx (*sem, timeout_ms, flags & MONO_SEM_FLAGS_ALERTABLE);
257
258         if (res == WAIT_IO_COMPLETION && !(flags & MONO_SEM_FLAGS_ALERTABLE))
259                 goto retry;
260
261         return res != WAIT_OBJECT_0 ? -1 : 0;
262 }
263
264 static inline int
265 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
266 {
267         return mono_os_sem_timedwait (sem, INFINITE, flags);
268 }
269
270 static inline int
271 mono_os_sem_post (MonoSemType *sem)
272 {
273         return !ReleaseSemaphore (*sem, 1, NULL) ? -1 : 0;
274 }
275
276 #endif
277
278 G_END_DECLS
279
280 #endif /* _MONO_SEMAPHORE_H_ */