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,
54 #if defined(USE_MACH_SEMA)
56 typedef semaphore_t MonoSemType;
59 mono_os_sem_init (MonoSemType *sem, int value)
61 return semaphore_create (current_task (), sem, SYNC_POLICY_FIFO, value) != KERN_SUCCESS ? -1 : 0;
65 mono_os_sem_destroy (MonoSemType *sem)
67 return semaphore_destroy (current_task (), *sem) != KERN_SUCCESS ? -1 : 0;
71 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
76 res = semaphore_wait (*sem);
77 g_assert (res != KERN_INVALID_ARGUMENT);
79 if (res == KERN_ABORTED && !(flags & MONO_SEM_FLAGS_ALERTABLE))
82 return res != KERN_SUCCESS ? -1 : 0;
86 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
88 mach_timespec_t ts, copy;
89 struct timeval start, current;
92 if (timeout_ms == MONO_INFINITE_WAIT)
93 return mono_os_sem_wait (sem, flags);
95 ts.tv_sec = timeout_ms / 1000;
96 ts.tv_nsec = (timeout_ms % 1000) * 1000000;
97 while (ts.tv_nsec >= NSEC_PER_SEC) {
98 ts.tv_nsec -= NSEC_PER_SEC;
103 gettimeofday (&start, NULL);
106 res = semaphore_timedwait (*sem, ts);
107 g_assert (res != KERN_INVALID_ARGUMENT);
109 if (res == KERN_ABORTED && !(flags & MONO_SEM_FLAGS_ALERTABLE)) {
112 gettimeofday (¤t, NULL);
113 ts.tv_sec -= (current.tv_sec - start.tv_sec);
114 ts.tv_nsec -= (current.tv_usec - start.tv_usec) * 1000;
115 if (ts.tv_nsec < 0) {
116 if (ts.tv_sec <= 0) {
120 ts.tv_nsec += NSEC_PER_SEC;
131 return res != KERN_SUCCESS ? -1 : 0;
135 mono_os_sem_post (MonoSemType *sem)
139 res = semaphore_signal (*sem);
140 g_assert (res != KERN_INVALID_ARGUMENT);
142 if (res == KERN_ABORTED)
145 return res != KERN_SUCCESS ? -1 : 0;
148 #elif !defined(HOST_WIN32) && defined(HAVE_SEMAPHORE_H)
150 typedef sem_t MonoSemType;
153 mono_os_sem_init (MonoSemType *sem, int value)
155 return sem_init (sem, 0, value);
159 mono_os_sem_destroy (MonoSemType *sem)
161 return sem_destroy (sem);
165 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
170 res = sem_wait (sem);
172 g_assert (errno != EINVAL);
174 if (res == -1 && errno == EINTR && !(flags & MONO_SEM_FLAGS_ALERTABLE))
177 return res != 0 ? -1 : 0;
181 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
183 struct timespec ts, copy;
187 if (timeout_ms == 0) {
188 res = sem_trywait (sem) != 0 ? -1 : 0;
190 g_assert (errno != EINVAL);
192 return res != 0 ? -1 : 0;
195 if (timeout_ms == MONO_INFINITE_WAIT)
196 return mono_os_sem_wait (sem, flags);
198 gettimeofday (&t, NULL);
199 ts.tv_sec = timeout_ms / 1000 + t.tv_sec;
200 ts.tv_nsec = (timeout_ms % 1000) * 1000000 + t.tv_usec * 1000;
201 while (ts.tv_nsec >= NSEC_PER_SEC) {
202 ts.tv_nsec -= NSEC_PER_SEC;
209 #if defined(__native_client__) && defined(USE_NEWLIB)
210 res = sem_trywait (sem);
212 res = sem_timedwait (sem, &ts);
215 g_assert (errno != EINVAL);
217 if (res == -1 && errno == EINTR && !(flags & MONO_SEM_FLAGS_ALERTABLE)) {
222 return res != 0 ? -1 : 0;
226 mono_os_sem_post (MonoSemType *sem)
230 res = sem_post (sem);
232 g_assert (errno != EINVAL);
239 typedef HANDLE MonoSemType;
242 mono_os_sem_init (MonoSemType *sem, int value)
244 *sem = CreateSemaphore (NULL, value, 0x7FFFFFFF, NULL);
245 return *sem == NULL ? -1 : 0;
249 mono_os_sem_destroy (MonoSemType *sem)
251 return !CloseHandle (*sem) ? -1 : 0;
255 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
260 res = WaitForSingleObjectEx (*sem, timeout_ms, flags & MONO_SEM_FLAGS_ALERTABLE);
262 if (res == WAIT_IO_COMPLETION && !(flags & MONO_SEM_FLAGS_ALERTABLE))
265 return res != WAIT_OBJECT_0 ? -1 : 0;
269 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
271 return mono_os_sem_timedwait (sem, INFINITE, flags);
275 mono_os_sem_post (MonoSemType *sem)
277 return !ReleaseSemaphore (*sem, 1, NULL) ? -1 : 0;
284 #endif /* _MONO_SEMAPHORE_H_ */