2 * mono-os-semaphore.h: Definitions for generic semaphore usage
5 * Geoff Norton <gnorton@novell.com>
7 * (C) 2009 Novell, Inc.
10 #ifndef _MONO_SEMAPHORE_H_
11 #define _MONO_SEMAPHORE_H_
18 #ifdef HAVE_SYS_TIME_H
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>
37 #define MONO_HAS_SEMAPHORES 1
40 #define NSEC_PER_SEC (1000 * 1000 * 1000)
43 #ifndef MONO_INFINITE_WAIT
44 #define MONO_INFINITE_WAIT ((guint32) 0xFFFFFFFF)
50 MONO_SEM_FLAGS_NONE = 0,
51 MONO_SEM_FLAGS_ALERTABLE = 1 << 0,
55 MONO_SEM_TIMEDWAIT_RET_SUCCESS = 0,
56 MONO_SEM_TIMEDWAIT_RET_ALERTED = -1,
57 MONO_SEM_TIMEDWAIT_RET_TIMEDOUT = -2,
58 } MonoSemTimedwaitRet;
60 #if defined(USE_MACH_SEMA)
62 typedef semaphore_t MonoSemType;
65 mono_os_sem_init (MonoSemType *sem, int value)
69 res = semaphore_create (current_task (), sem, SYNC_POLICY_FIFO, value);
70 if (G_UNLIKELY (res != KERN_SUCCESS))
71 g_error ("%s: semaphore_create failed with error %d", __func__, res);
75 mono_os_sem_destroy (MonoSemType *sem)
79 res = semaphore_destroy (current_task (), *sem);
80 if (G_UNLIKELY (res != KERN_SUCCESS))
81 g_error ("%s: semaphore_destroy failed with error %d", __func__, res);
85 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
90 res = semaphore_wait (*sem);
91 if (G_UNLIKELY (res != KERN_SUCCESS && res != KERN_ABORTED))
92 g_error ("%s: semaphore_wait failed with error %d", __func__, res);
94 if (res == KERN_ABORTED && !(flags & MONO_SEM_FLAGS_ALERTABLE))
97 return res != KERN_SUCCESS ? -1 : 0;
100 static inline MonoSemTimedwaitRet
101 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
105 mach_timespec_t ts, copy;
106 struct timeval start, current;
108 if (timeout_ms == MONO_INFINITE_WAIT)
109 return (MonoSemTimedwaitRet) mono_os_sem_wait (sem, flags);
111 ts.tv_sec = timeout_ms / 1000;
112 ts.tv_nsec = (timeout_ms % 1000) * 1000000;
113 while (ts.tv_nsec >= NSEC_PER_SEC) {
114 ts.tv_nsec -= NSEC_PER_SEC;
119 resint = gettimeofday (&start, NULL);
120 if (G_UNLIKELY (resint != 0))
121 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
124 res = semaphore_timedwait (*sem, ts);
125 if (G_UNLIKELY (res != KERN_SUCCESS && res != KERN_ABORTED && res != KERN_OPERATION_TIMED_OUT))
126 g_error ("%s: semaphore_timedwait failed with error %d", __func__, res);
128 if (res == KERN_ABORTED && !(flags & MONO_SEM_FLAGS_ALERTABLE)) {
131 resint = gettimeofday (¤t, NULL);
132 if (G_UNLIKELY (resint != 0))
133 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
135 ts.tv_sec -= (current.tv_sec - start.tv_sec);
136 ts.tv_nsec -= (current.tv_usec - start.tv_usec) * 1000;
137 if (ts.tv_nsec < 0) {
138 if (ts.tv_sec <= 0) {
142 ts.tv_nsec += NSEC_PER_SEC;
155 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
157 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
158 case KERN_OPERATION_TIMED_OUT:
159 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
161 g_assert_not_reached ();
166 mono_os_sem_post (MonoSemType *sem)
171 res = semaphore_signal (*sem);
172 if (G_UNLIKELY (res != KERN_SUCCESS && res != KERN_ABORTED))
173 g_error ("%s: semaphore_signal failed with error %d", __func__, res);
175 if (res == KERN_ABORTED)
179 #elif !defined(HOST_WIN32) && defined(HAVE_SEMAPHORE_H)
181 typedef sem_t MonoSemType;
184 mono_os_sem_init (MonoSemType *sem, int value)
188 res = sem_init (sem, 0, value);
189 if (G_UNLIKELY (res != 0))
190 g_error ("%s: sem_init failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
194 mono_os_sem_destroy (MonoSemType *sem)
198 res = sem_destroy (sem);
199 if (G_UNLIKELY (res != 0))
200 g_error ("%s: sem_destroy failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
204 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
209 res = sem_wait (sem);
210 if (G_UNLIKELY (res != 0 && errno != EINTR))
211 g_error ("%s: sem_wait failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
213 if (res != 0 && errno == EINTR && !(flags & MONO_SEM_FLAGS_ALERTABLE))
216 return res != 0 ? -1 : 0;
219 static inline MonoSemTimedwaitRet
220 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
222 struct timespec ts, copy;
226 if (timeout_ms == 0) {
227 res = sem_trywait (sem);
228 if (G_UNLIKELY (res != 0 && errno != EINTR && errno != EAGAIN))
229 g_error ("%s: sem_trywait failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
232 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
233 else if (errno == EINTR)
234 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
235 else if (errno == EAGAIN)
236 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
238 g_assert_not_reached ();
241 if (timeout_ms == MONO_INFINITE_WAIT)
242 return (MonoSemTimedwaitRet) mono_os_sem_wait (sem, flags);
244 res = gettimeofday (&t, NULL);
245 if (G_UNLIKELY (res != 0))
246 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
248 ts.tv_sec = timeout_ms / 1000 + t.tv_sec;
249 ts.tv_nsec = (timeout_ms % 1000) * 1000000 + t.tv_usec * 1000;
250 while (ts.tv_nsec >= NSEC_PER_SEC) {
251 ts.tv_nsec -= NSEC_PER_SEC;
258 res = sem_timedwait (sem, &ts);
259 if (G_UNLIKELY (res != 0 && errno != EINTR && errno != ETIMEDOUT))
260 g_error ("%s: sem_timedwait failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
262 if (res != 0 && errno == EINTR && !(flags & MONO_SEM_FLAGS_ALERTABLE)) {
268 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
269 else if (errno == EINTR)
270 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
271 else if (errno == ETIMEDOUT)
272 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
274 g_assert_not_reached ();
278 mono_os_sem_post (MonoSemType *sem)
282 res = sem_post (sem);
283 if (G_UNLIKELY (res != 0))
284 g_error ("%s: sem_post failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
289 typedef HANDLE MonoSemType;
292 mono_os_sem_init (MonoSemType *sem, int value)
294 *sem = CreateSemaphore (NULL, value, 0x7FFFFFFF, NULL);
295 if (G_UNLIKELY (*sem == NULL))
296 g_error ("%s: CreateSemaphore failed with error %d", __func__, GetLastError ());
300 mono_os_sem_destroy (MonoSemType *sem)
304 res = CloseHandle (*sem);
305 if (G_UNLIKELY (res == 0))
306 g_error ("%s: CloseHandle failed with error %d", __func__, GetLastError ());
309 static inline MonoSemTimedwaitRet
310 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
315 res = WaitForSingleObjectEx (*sem, timeout_ms, flags & MONO_SEM_FLAGS_ALERTABLE);
316 if (G_UNLIKELY (res != WAIT_OBJECT_0 && res != WAIT_IO_COMPLETION && res != WAIT_TIMEOUT))
317 g_error ("%s: WaitForSingleObjectEx failed with error %d", __func__, GetLastError ());
319 if (res == WAIT_IO_COMPLETION && !(flags & MONO_SEM_FLAGS_ALERTABLE))
324 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
325 case WAIT_IO_COMPLETION:
326 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
328 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
330 g_assert_not_reached ();
335 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
337 return mono_os_sem_timedwait (sem, INFINITE, flags) != 0 ? -1 : 0;
341 mono_os_sem_post (MonoSemType *sem)
345 res = ReleaseSemaphore (*sem, 1, NULL);
346 if (G_UNLIKELY (res == 0))
347 g_error ("%s: ReleaseSemaphore failed with error %d", __func__, GetLastError ());
354 #endif /* _MONO_SEMAPHORE_H_ */