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)
46 MONO_SEM_FLAGS_NONE = 0,
47 MONO_SEM_FLAGS_ALERTABLE = 1 << 0,
50 #if defined(USE_MACH_SEMA)
52 typedef semaphore_t MonoSemType;
55 mono_os_sem_init (MonoSemType *sem, int value)
57 return semaphore_create (current_task (), sem, SYNC_POLICY_FIFO, value) != KERN_SUCCESS ? -1 : 0;
61 mono_os_sem_destroy (MonoSemType *sem)
63 return semaphore_destroy (current_task (), *sem) != KERN_SUCCESS ? -1 : 0;
67 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
72 res = semaphore_wait (*sem);
73 g_assert (res != KERN_INVALID_ARGUMENT);
75 if (res == KERN_ABORTED && !(flags & MONO_SEM_FLAGS_ALERTABLE))
78 return res != KERN_SUCCESS ? -1 : 0;
82 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
84 mach_timespec_t ts, copy;
85 struct timeval start, current;
88 if (timeout_ms == (guint32) 0xFFFFFFFF)
89 return mono_os_sem_wait (sem, flags);
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;
99 gettimeofday (&start, NULL);
102 res = semaphore_timedwait (*sem, ts);
103 g_assert (res != KERN_INVALID_ARGUMENT);
105 if (res == KERN_ABORTED && !(flags & MONO_SEM_FLAGS_ALERTABLE)) {
108 gettimeofday (¤t, 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) {
116 ts.tv_nsec += NSEC_PER_SEC;
127 return res != KERN_SUCCESS ? -1 : 0;
131 mono_os_sem_post (MonoSemType *sem)
135 res = semaphore_signal (*sem);
136 g_assert (res != KERN_INVALID_ARGUMENT);
138 if (res == KERN_ABORTED)
141 return res != KERN_SUCCESS ? -1 : 0;
144 #elif !defined(HOST_WIN32) && defined(HAVE_SEMAPHORE_H)
146 typedef sem_t MonoSemType;
149 mono_os_sem_init (MonoSemType *sem, int value)
151 return sem_init (sem, 0, value);
155 mono_os_sem_destroy (MonoSemType *sem)
157 return sem_destroy (sem);
161 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
166 res = sem_wait (sem);
168 g_assert (errno != EINVAL);
170 if (res == -1 && errno == EINTR && !(flags & MONO_SEM_FLAGS_ALERTABLE))
173 return res != 0 ? -1 : 0;
177 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
179 struct timespec ts, copy;
183 if (timeout_ms == 0) {
184 res = sem_trywait (sem) != 0 ? -1 : 0;
186 g_assert (errno != EINVAL);
188 return res != 0 ? -1 : 0;
191 if (timeout_ms == (guint32) 0xFFFFFFFF)
192 return mono_os_sem_wait (sem, flags);
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;
205 #if defined(__native_client__) && defined(USE_NEWLIB)
206 res = sem_trywait (sem);
208 res = sem_timedwait (sem, &ts);
211 g_assert (errno != EINVAL);
213 if (res == -1 && errno == EINTR && !(flags & MONO_SEM_FLAGS_ALERTABLE)) {
218 return res != 0 ? -1 : 0;
222 mono_os_sem_post (MonoSemType *sem)
226 res = sem_post (sem);
228 g_assert (errno != EINVAL);
235 typedef HANDLE MonoSemType;
238 mono_os_sem_init (MonoSemType *sem, int value)
240 *sem = CreateSemaphore (NULL, value, 0x7FFFFFFF, NULL);
241 return *sem == NULL ? -1 : 0;
245 mono_os_sem_destroy (MonoSemType *sem)
247 return !CloseHandle (*sem) ? -1 : 0;
251 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
256 res = WaitForSingleObjectEx (*sem, timeout_ms, flags & MONO_SEM_FLAGS_ALERTABLE);
258 if (res == WAIT_IO_COMPLETION && !(flags & MONO_SEM_FLAGS_ALERTABLE))
261 return res != WAIT_OBJECT_0 ? -1 : 0;
265 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
267 return mono_os_sem_timedwait (sem, INFINITE, flags);
271 mono_os_sem_post (MonoSemType *sem)
273 return !ReleaseSemaphore (*sem, 1, NULL) ? -1 : 0;
280 #endif /* _MONO_SEMAPHORE_H_ */