3 * Definitions for generic semaphore usage
6 * Geoff Norton <gnorton@novell.com>
8 * (C) 2009 Novell, Inc.
11 #ifndef _MONO_SEMAPHORE_H_
12 #define _MONO_SEMAPHORE_H_
19 #ifdef HAVE_SYS_TIME_H
27 #if defined(USE_MACH_SEMA)
28 #include <mach/mach_init.h>
29 #include <mach/task.h>
30 #include <mach/semaphore.h>
31 #elif !defined(HOST_WIN32) && defined(HAVE_SEMAPHORE_H)
32 #include <semaphore.h>
38 #define MONO_HAS_SEMAPHORES 1
41 #define NSEC_PER_SEC (1000 * 1000 * 1000)
44 #ifndef MONO_INFINITE_WAIT
45 #define MONO_INFINITE_WAIT ((guint32) 0xFFFFFFFF)
51 MONO_SEM_FLAGS_NONE = 0,
52 MONO_SEM_FLAGS_ALERTABLE = 1 << 0,
56 MONO_SEM_TIMEDWAIT_RET_SUCCESS = 0,
57 MONO_SEM_TIMEDWAIT_RET_ALERTED = -1,
58 MONO_SEM_TIMEDWAIT_RET_TIMEDOUT = -2,
59 } MonoSemTimedwaitRet;
61 #if defined(USE_MACH_SEMA)
63 typedef semaphore_t MonoSemType;
66 mono_os_sem_init (MonoSemType *sem, int value)
70 res = semaphore_create (current_task (), sem, SYNC_POLICY_FIFO, value);
71 if (G_UNLIKELY (res != KERN_SUCCESS))
72 g_error ("%s: semaphore_create failed with error %d", __func__, res);
76 mono_os_sem_destroy (MonoSemType *sem)
80 res = semaphore_destroy (current_task (), *sem);
81 if (G_UNLIKELY (res != KERN_SUCCESS))
82 g_error ("%s: semaphore_destroy failed with error %d", __func__, res);
86 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
91 res = semaphore_wait (*sem);
92 if (G_UNLIKELY (res != KERN_SUCCESS && res != KERN_ABORTED))
93 g_error ("%s: semaphore_wait failed with error %d", __func__, res);
95 if (res == KERN_ABORTED && !(flags & MONO_SEM_FLAGS_ALERTABLE))
98 return res != KERN_SUCCESS ? -1 : 0;
101 static inline MonoSemTimedwaitRet
102 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
106 mach_timespec_t ts, copy;
107 struct timeval start, current;
109 if (timeout_ms == MONO_INFINITE_WAIT)
110 return (MonoSemTimedwaitRet) mono_os_sem_wait (sem, flags);
112 ts.tv_sec = timeout_ms / 1000;
113 ts.tv_nsec = (timeout_ms % 1000) * 1000000;
114 while (ts.tv_nsec >= NSEC_PER_SEC) {
115 ts.tv_nsec -= NSEC_PER_SEC;
120 resint = gettimeofday (&start, NULL);
121 if (G_UNLIKELY (resint != 0))
122 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
125 res = semaphore_timedwait (*sem, ts);
126 if (G_UNLIKELY (res != KERN_SUCCESS && res != KERN_ABORTED && res != KERN_OPERATION_TIMED_OUT))
127 g_error ("%s: semaphore_timedwait failed with error %d", __func__, res);
129 if (res == KERN_ABORTED && !(flags & MONO_SEM_FLAGS_ALERTABLE)) {
132 resint = gettimeofday (¤t, NULL);
133 if (G_UNLIKELY (resint != 0))
134 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
136 ts.tv_sec -= (current.tv_sec - start.tv_sec);
137 ts.tv_nsec -= (current.tv_usec - start.tv_usec) * 1000;
138 if (ts.tv_nsec < 0) {
139 if (ts.tv_sec <= 0) {
143 ts.tv_nsec += NSEC_PER_SEC;
156 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
158 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
159 case KERN_OPERATION_TIMED_OUT:
160 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
162 g_assert_not_reached ();
167 mono_os_sem_post (MonoSemType *sem)
172 res = semaphore_signal (*sem);
173 if (G_UNLIKELY (res != KERN_SUCCESS && res != KERN_ABORTED))
174 g_error ("%s: semaphore_signal failed with error %d", __func__, res);
176 if (res == KERN_ABORTED)
180 #elif !defined(HOST_WIN32) && defined(HAVE_SEMAPHORE_H)
182 typedef sem_t MonoSemType;
185 mono_os_sem_init (MonoSemType *sem, int value)
189 res = sem_init (sem, 0, value);
190 if (G_UNLIKELY (res != 0))
191 g_error ("%s: sem_init failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
195 mono_os_sem_destroy (MonoSemType *sem)
199 res = sem_destroy (sem);
200 if (G_UNLIKELY (res != 0))
201 g_error ("%s: sem_destroy failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
205 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
210 res = sem_wait (sem);
211 if (G_UNLIKELY (res != 0 && errno != EINTR))
212 g_error ("%s: sem_wait failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
214 if (res != 0 && errno == EINTR && !(flags & MONO_SEM_FLAGS_ALERTABLE))
217 return res != 0 ? -1 : 0;
220 static inline MonoSemTimedwaitRet
221 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
223 struct timespec ts, copy;
227 if (timeout_ms == 0) {
228 res = sem_trywait (sem);
229 if (G_UNLIKELY (res != 0 && errno != EINTR && errno != EAGAIN))
230 g_error ("%s: sem_trywait failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
233 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
234 else if (errno == EINTR)
235 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
236 else if (errno == EAGAIN)
237 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
239 g_assert_not_reached ();
242 if (timeout_ms == MONO_INFINITE_WAIT)
243 return (MonoSemTimedwaitRet) mono_os_sem_wait (sem, flags);
245 res = gettimeofday (&t, NULL);
246 if (G_UNLIKELY (res != 0))
247 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
249 ts.tv_sec = timeout_ms / 1000 + t.tv_sec;
250 ts.tv_nsec = (timeout_ms % 1000) * 1000000 + t.tv_usec * 1000;
251 while (ts.tv_nsec >= NSEC_PER_SEC) {
252 ts.tv_nsec -= NSEC_PER_SEC;
259 res = sem_timedwait (sem, &ts);
260 if (G_UNLIKELY (res != 0 && errno != EINTR && errno != ETIMEDOUT))
261 g_error ("%s: sem_timedwait failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
263 if (res != 0 && errno == EINTR && !(flags & MONO_SEM_FLAGS_ALERTABLE)) {
269 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
270 else if (errno == EINTR)
271 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
272 else if (errno == ETIMEDOUT)
273 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
275 g_assert_not_reached ();
279 mono_os_sem_post (MonoSemType *sem)
283 res = sem_post (sem);
284 if (G_UNLIKELY (res != 0))
285 g_error ("%s: sem_post failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
290 typedef HANDLE MonoSemType;
293 mono_os_sem_init (MonoSemType *sem, int value)
295 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
296 *sem = CreateSemaphore (NULL, value, 0x7FFFFFFF, NULL);
298 *sem = CreateSemaphoreEx (NULL, value, 0x7FFFFFFF, NULL, 0, SEMAPHORE_ALL_ACCESS);
301 if (G_UNLIKELY (*sem == NULL))
302 g_error ("%s: CreateSemaphore failed with error %d", __func__, GetLastError ());
306 mono_os_sem_destroy (MonoSemType *sem)
310 res = CloseHandle (*sem);
311 if (G_UNLIKELY (res == 0))
312 g_error ("%s: CloseHandle failed with error %d", __func__, GetLastError ());
315 static inline MonoSemTimedwaitRet
316 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
321 res = WaitForSingleObjectEx (*sem, timeout_ms, flags & MONO_SEM_FLAGS_ALERTABLE);
322 if (G_UNLIKELY (res != WAIT_OBJECT_0 && res != WAIT_IO_COMPLETION && res != WAIT_TIMEOUT))
323 g_error ("%s: WaitForSingleObjectEx failed with error %d", __func__, GetLastError ());
325 if (res == WAIT_IO_COMPLETION && !(flags & MONO_SEM_FLAGS_ALERTABLE))
330 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
331 case WAIT_IO_COMPLETION:
332 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
334 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
336 g_assert_not_reached ();
341 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
343 return mono_os_sem_timedwait (sem, MONO_INFINITE_WAIT, flags) != 0 ? -1 : 0;
347 mono_os_sem_post (MonoSemType *sem)
351 res = ReleaseSemaphore (*sem, 1, NULL);
352 if (G_UNLIKELY (res == 0))
353 g_error ("%s: ReleaseSemaphore failed with error %d", __func__, GetLastError ());
360 #endif /* _MONO_SEMAPHORE_H_ */