Update Haiku support (#15674)
[mono-project.git] / mono / utils / mono-os-semaphore.h
bloba2962c187a8312e69656e2d90faf34fc64108579
1 /**
2 * \file
3 * Definitions for generic semaphore usage
5 * Author:
6 * Geoff Norton <gnorton@novell.com>
8 * (C) 2009 Novell, Inc.
9 */
11 #ifndef _MONO_SEMAPHORE_H_
12 #define _MONO_SEMAPHORE_H_
14 #include <config.h>
15 #include <glib.h>
17 #include <errno.h>
19 #ifdef HAVE_SYS_TIME_H
20 #include <sys/time.h>
21 #endif
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
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>
33 #else
34 #include <mono/utils/mono-os-wait.h>
35 #endif
37 #define MONO_HAS_SEMAPHORES 1
39 #define MONO_NSEC_PER_SEC (1000 * 1000 * 1000)
41 #define MONO_INFINITE_WAIT ((guint32) 0xFFFFFFFF)
43 typedef enum {
44 MONO_SEM_FLAGS_NONE = 0,
45 MONO_SEM_FLAGS_ALERTABLE = 1 << 0,
46 } MonoSemFlags;
48 typedef enum {
49 MONO_SEM_TIMEDWAIT_RET_SUCCESS = 0,
50 MONO_SEM_TIMEDWAIT_RET_ALERTED = -1,
51 MONO_SEM_TIMEDWAIT_RET_TIMEDOUT = -2,
52 } MonoSemTimedwaitRet;
54 #if defined(USE_MACH_SEMA)
56 typedef semaphore_t MonoSemType;
58 static inline void
59 mono_os_sem_init (MonoSemType *sem, int value)
61 kern_return_t res;
63 res = semaphore_create (current_task (), sem, SYNC_POLICY_FIFO, value);
64 if (G_UNLIKELY (res != KERN_SUCCESS))
65 g_error ("%s: semaphore_create failed with error %d", __func__, res);
68 static inline void
69 mono_os_sem_destroy (MonoSemType *sem)
71 kern_return_t res;
73 res = semaphore_destroy (current_task (), *sem);
74 if (G_UNLIKELY (res != KERN_SUCCESS))
75 g_error ("%s: semaphore_destroy failed with error %d", __func__, res);
78 static inline int
79 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
81 kern_return_t res;
83 retry:
84 res = semaphore_wait (*sem);
85 if (G_UNLIKELY (res != KERN_SUCCESS && res != KERN_ABORTED))
86 g_error ("%s: semaphore_wait failed with error %d", __func__, res);
88 if (res == KERN_ABORTED && !(flags & MONO_SEM_FLAGS_ALERTABLE))
89 goto retry;
91 return res != KERN_SUCCESS ? -1 : 0;
94 static inline MonoSemTimedwaitRet
95 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
97 kern_return_t res;
98 int resint;
99 mach_timespec_t ts, copy;
100 struct timeval start, current;
102 if (timeout_ms == MONO_INFINITE_WAIT)
103 return (MonoSemTimedwaitRet) mono_os_sem_wait (sem, flags);
105 ts.tv_sec = timeout_ms / 1000;
106 ts.tv_nsec = (timeout_ms % 1000) * 1000000;
107 while (ts.tv_nsec >= MONO_NSEC_PER_SEC) {
108 ts.tv_nsec -= MONO_NSEC_PER_SEC;
109 ts.tv_sec++;
112 copy = ts;
113 resint = gettimeofday (&start, NULL);
114 if (G_UNLIKELY (resint != 0))
115 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
117 retry:
118 res = semaphore_timedwait (*sem, ts);
119 if (G_UNLIKELY (res != KERN_SUCCESS && res != KERN_ABORTED && res != KERN_OPERATION_TIMED_OUT))
120 g_error ("%s: semaphore_timedwait failed with error %d", __func__, res);
122 if (res == KERN_ABORTED && !(flags & MONO_SEM_FLAGS_ALERTABLE)) {
123 ts = copy;
125 resint = gettimeofday (&current, NULL);
126 if (G_UNLIKELY (resint != 0))
127 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
129 ts.tv_sec -= (current.tv_sec - start.tv_sec);
130 ts.tv_nsec -= (current.tv_usec - start.tv_usec) * 1000;
131 if (ts.tv_nsec < 0) {
132 if (ts.tv_sec <= 0) {
133 ts.tv_nsec = 0;
134 } else {
135 ts.tv_sec--;
136 ts.tv_nsec += MONO_NSEC_PER_SEC;
139 if (ts.tv_sec < 0) {
140 ts.tv_sec = 0;
141 ts.tv_nsec = 0;
144 goto retry;
147 switch (res) {
148 case KERN_SUCCESS:
149 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
150 case KERN_ABORTED:
151 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
152 case KERN_OPERATION_TIMED_OUT:
153 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
154 default:
155 g_assert_not_reached ();
159 static inline void
160 mono_os_sem_post (MonoSemType *sem)
162 kern_return_t res;
164 retry:
165 res = semaphore_signal (*sem);
166 if (G_UNLIKELY (res != KERN_SUCCESS && res != KERN_ABORTED))
167 g_error ("%s: semaphore_signal failed with error %d", __func__, res);
169 if (res == KERN_ABORTED)
170 goto retry;
173 #elif !defined(HOST_WIN32) && defined(HAVE_SEMAPHORE_H)
175 typedef sem_t MonoSemType;
177 static inline void
178 mono_os_sem_init (MonoSemType *sem, int value)
180 int res;
182 res = sem_init (sem, 0, value);
183 if (G_UNLIKELY (res != 0))
184 g_error ("%s: sem_init failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
187 static inline void
188 mono_os_sem_destroy (MonoSemType *sem)
190 int res;
192 res = sem_destroy (sem);
193 if (G_UNLIKELY (res != 0))
194 g_error ("%s: sem_destroy failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
197 static inline int
198 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
200 int res;
202 retry:
203 res = sem_wait (sem);
204 if (G_UNLIKELY (res != 0 && errno != EINTR))
205 g_error ("%s: sem_wait failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
207 if (res != 0 && errno == EINTR && !(flags & MONO_SEM_FLAGS_ALERTABLE))
208 goto retry;
210 return res != 0 ? -1 : 0;
213 static inline MonoSemTimedwaitRet
214 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
216 struct timespec ts, copy;
217 struct timeval t;
218 int res;
220 if (timeout_ms == 0) {
221 res = sem_trywait (sem);
222 if (G_UNLIKELY (res != 0 && errno != EINTR && errno != EAGAIN))
223 g_error ("%s: sem_trywait failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
225 if (res == 0)
226 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
227 else if (errno == EINTR)
228 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
229 else if (errno == EAGAIN)
230 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
231 else
232 g_assert_not_reached ();
235 if (timeout_ms == MONO_INFINITE_WAIT)
236 return (MonoSemTimedwaitRet) mono_os_sem_wait (sem, flags);
238 res = gettimeofday (&t, NULL);
239 if (G_UNLIKELY (res != 0))
240 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
242 ts.tv_sec = timeout_ms / 1000 + t.tv_sec;
243 ts.tv_nsec = (timeout_ms % 1000) * 1000000 + t.tv_usec * 1000;
244 while (ts.tv_nsec >= MONO_NSEC_PER_SEC) {
245 ts.tv_nsec -= MONO_NSEC_PER_SEC;
246 ts.tv_sec++;
249 copy = ts;
251 retry:
252 res = sem_timedwait (sem, &ts);
253 if (G_UNLIKELY (res != 0 && errno != EINTR && errno != ETIMEDOUT))
254 g_error ("%s: sem_timedwait failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
256 if (res != 0 && errno == EINTR && !(flags & MONO_SEM_FLAGS_ALERTABLE)) {
257 ts = copy;
258 goto retry;
261 if (res == 0)
262 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
263 else if (errno == EINTR)
264 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
265 else if (errno == ETIMEDOUT)
266 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
267 else
268 g_assert_not_reached ();
271 static inline void
272 mono_os_sem_post (MonoSemType *sem)
274 int res;
276 res = sem_post (sem);
277 if (G_UNLIKELY (res != 0))
278 g_error ("%s: sem_post failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
281 #else
283 #include <mono/utils/mono-compiler.h>
285 typedef HANDLE MonoSemType;
287 static inline void
288 mono_os_sem_init (MonoSemType *sem, int value)
290 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
291 *sem = CreateSemaphore (NULL, value, 0x7FFFFFFF, NULL);
292 #else
293 *sem = CreateSemaphoreEx (NULL, value, 0x7FFFFFFF, NULL, 0, SEMAPHORE_ALL_ACCESS);
294 #endif
296 if (G_UNLIKELY (*sem == NULL))
297 g_error ("%s: CreateSemaphore failed with error %d", __func__, GetLastError ());
300 static inline void
301 mono_os_sem_destroy (MonoSemType *sem)
303 BOOL res;
305 res = CloseHandle (*sem);
306 if (G_UNLIKELY (res == 0))
307 g_error ("%s: CloseHandle failed with error %d", __func__, GetLastError ());
310 MONO_PROFILER_API MonoSemTimedwaitRet
311 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags);
313 static inline int
314 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
316 return mono_os_sem_timedwait (sem, MONO_INFINITE_WAIT, flags) != 0 ? -1 : 0;
319 static inline void
320 mono_os_sem_post (MonoSemType *sem)
322 BOOL res;
324 res = ReleaseSemaphore (*sem, 1, NULL);
325 if (G_UNLIKELY (res == 0))
326 g_error ("%s: ReleaseSemaphore failed with error %d", __func__, GetLastError ());
329 #endif
331 #endif /* _MONO_SEMAPHORE_H_ */