update readme (#21797)
[mono-project.git] / mono / utils / mono-os-semaphore.h
blobbf06c79efcbd3f3f5cc47e84796777971cab6ada
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
36 #include <mono/utils/w32subset.h>
38 #define MONO_HAS_SEMAPHORES 1
40 #define MONO_NSEC_PER_SEC (1000 * 1000 * 1000)
42 #define MONO_INFINITE_WAIT ((guint32) 0xFFFFFFFF)
44 typedef enum {
45 MONO_SEM_FLAGS_NONE = 0,
46 MONO_SEM_FLAGS_ALERTABLE = 1 << 0,
47 } MonoSemFlags;
49 typedef enum {
50 MONO_SEM_TIMEDWAIT_RET_SUCCESS = 0,
51 MONO_SEM_TIMEDWAIT_RET_ALERTED = -1,
52 MONO_SEM_TIMEDWAIT_RET_TIMEDOUT = -2,
53 } MonoSemTimedwaitRet;
55 #if defined(USE_MACH_SEMA)
57 typedef semaphore_t MonoSemType;
59 static inline void
60 mono_os_sem_init (MonoSemType *sem, int value)
62 kern_return_t res;
64 res = semaphore_create (current_task (), sem, SYNC_POLICY_FIFO, value);
65 if (G_UNLIKELY (res != KERN_SUCCESS))
66 g_error ("%s: semaphore_create failed with error %d", __func__, res);
69 static inline void
70 mono_os_sem_destroy (MonoSemType *sem)
72 kern_return_t res;
74 res = semaphore_destroy (current_task (), *sem);
75 if (G_UNLIKELY (res != KERN_SUCCESS))
76 g_error ("%s: semaphore_destroy failed with error %d", __func__, res);
79 static inline int
80 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
82 kern_return_t res;
84 retry:
85 res = semaphore_wait (*sem);
86 if (G_UNLIKELY (res != KERN_SUCCESS && res != KERN_ABORTED))
87 g_error ("%s: semaphore_wait failed with error %d", __func__, res);
89 if (res == KERN_ABORTED && !(flags & MONO_SEM_FLAGS_ALERTABLE))
90 goto retry;
92 return res != KERN_SUCCESS ? -1 : 0;
95 static inline MonoSemTimedwaitRet
96 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
98 kern_return_t res;
99 int resint;
100 mach_timespec_t ts, copy;
101 struct timeval start, current;
103 if (timeout_ms == MONO_INFINITE_WAIT)
104 return (MonoSemTimedwaitRet) mono_os_sem_wait (sem, flags);
106 ts.tv_sec = timeout_ms / 1000;
107 ts.tv_nsec = (timeout_ms % 1000) * 1000000;
108 while (ts.tv_nsec >= MONO_NSEC_PER_SEC) {
109 ts.tv_nsec -= MONO_NSEC_PER_SEC;
110 ts.tv_sec++;
113 copy = ts;
114 resint = gettimeofday (&start, NULL);
115 if (G_UNLIKELY (resint != 0))
116 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
118 retry:
119 res = semaphore_timedwait (*sem, ts);
120 if (G_UNLIKELY (res != KERN_SUCCESS && res != KERN_ABORTED && res != KERN_OPERATION_TIMED_OUT))
121 g_error ("%s: semaphore_timedwait failed with error %d", __func__, res);
123 if (res == KERN_ABORTED && !(flags & MONO_SEM_FLAGS_ALERTABLE)) {
124 ts = copy;
126 resint = gettimeofday (&current, NULL);
127 if (G_UNLIKELY (resint != 0))
128 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
130 ts.tv_sec -= (current.tv_sec - start.tv_sec);
131 ts.tv_nsec -= (current.tv_usec - start.tv_usec) * 1000;
132 if (ts.tv_nsec < 0) {
133 if (ts.tv_sec <= 0) {
134 ts.tv_nsec = 0;
135 } else {
136 ts.tv_sec--;
137 ts.tv_nsec += MONO_NSEC_PER_SEC;
140 if (ts.tv_sec < 0) {
141 ts.tv_sec = 0;
142 ts.tv_nsec = 0;
145 goto retry;
148 switch (res) {
149 case KERN_SUCCESS:
150 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
151 case KERN_ABORTED:
152 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
153 case KERN_OPERATION_TIMED_OUT:
154 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
155 default:
156 g_assert_not_reached ();
160 static inline void
161 mono_os_sem_post (MonoSemType *sem)
163 kern_return_t res;
165 retry:
166 res = semaphore_signal (*sem);
167 if (G_UNLIKELY (res != KERN_SUCCESS && res != KERN_ABORTED))
168 g_error ("%s: semaphore_signal failed with error %d", __func__, res);
170 if (res == KERN_ABORTED)
171 goto retry;
174 #elif !defined(HOST_WIN32) && defined(HAVE_SEMAPHORE_H)
176 typedef sem_t MonoSemType;
178 static inline void
179 mono_os_sem_init (MonoSemType *sem, int value)
181 int res;
183 res = sem_init (sem, 0, value);
184 if (G_UNLIKELY (res != 0))
185 g_error ("%s: sem_init failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
188 static inline void
189 mono_os_sem_destroy (MonoSemType *sem)
191 int res;
193 res = sem_destroy (sem);
194 if (G_UNLIKELY (res != 0))
195 g_error ("%s: sem_destroy failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
198 static inline int
199 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
201 int res;
203 retry:
204 res = sem_wait (sem);
205 if (G_UNLIKELY (res != 0 && errno != EINTR))
206 g_error ("%s: sem_wait failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
208 if (res != 0 && errno == EINTR && !(flags & MONO_SEM_FLAGS_ALERTABLE))
209 goto retry;
211 return res != 0 ? -1 : 0;
214 static inline MonoSemTimedwaitRet
215 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
217 struct timespec ts, copy;
218 struct timeval t;
219 int res;
221 if (timeout_ms == 0) {
222 res = sem_trywait (sem);
223 if (G_UNLIKELY (res != 0 && errno != EINTR && errno != EAGAIN))
224 g_error ("%s: sem_trywait failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
226 if (res == 0)
227 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
228 else if (errno == EINTR)
229 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
230 else if (errno == EAGAIN)
231 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
232 else
233 g_assert_not_reached ();
236 if (timeout_ms == MONO_INFINITE_WAIT)
237 return (MonoSemTimedwaitRet) mono_os_sem_wait (sem, flags);
239 res = gettimeofday (&t, NULL);
240 if (G_UNLIKELY (res != 0))
241 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
243 ts.tv_sec = timeout_ms / 1000 + t.tv_sec;
244 ts.tv_nsec = (timeout_ms % 1000) * 1000000 + t.tv_usec * 1000;
245 while (ts.tv_nsec >= MONO_NSEC_PER_SEC) {
246 ts.tv_nsec -= MONO_NSEC_PER_SEC;
247 ts.tv_sec++;
250 copy = ts;
252 retry:
253 res = sem_timedwait (sem, &ts);
254 if (G_UNLIKELY (res != 0 && errno != EINTR && errno != ETIMEDOUT))
255 g_error ("%s: sem_timedwait failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
257 if (res != 0 && errno == EINTR && !(flags & MONO_SEM_FLAGS_ALERTABLE)) {
258 ts = copy;
259 goto retry;
262 if (res == 0)
263 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
264 else if (errno == EINTR)
265 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
266 else if (errno == ETIMEDOUT)
267 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
268 else
269 g_assert_not_reached ();
272 static inline void
273 mono_os_sem_post (MonoSemType *sem)
275 int res;
277 res = sem_post (sem);
278 if (G_UNLIKELY (res != 0))
279 g_error ("%s: sem_post failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
282 #else
284 #include <mono/utils/mono-compiler.h>
286 typedef HANDLE MonoSemType;
288 #if HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE || HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE_EX
289 static inline void
290 mono_os_sem_init (MonoSemType *sem, int value)
292 #if HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE
293 *sem = CreateSemaphoreW (NULL, value, 0x7FFFFFFF, NULL);
294 #elif HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE_EX
295 *sem = CreateSemaphoreExW (NULL, value, 0x7FFFFFFF, NULL, 0, SEMAPHORE_ALL_ACCESS);
296 #endif
297 if (G_UNLIKELY (*sem == NULL))
298 g_error ("%s: CreateSemaphore failed with error %d", __func__, GetLastError ());
300 #elif !HAVE_EXTERN_DEFINED_WIN32_CREATE_SEMAPHORE && !HAVE_EXTERN_DEFINED_WIN32_CREATE_SEMAPHORE_EX
301 static inline void
302 mono_os_sem_init (MonoSemType *sem, int value)
304 *sem = NULL;
305 g_unsupported_api ("CreateSemaphore, CreateSemaphoreEx");
306 SetLastError (ERROR_NOT_SUPPORTED);
308 #endif /* HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE || HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE_EX */
310 static inline void
311 mono_os_sem_destroy (MonoSemType *sem)
313 BOOL res;
315 res = CloseHandle (*sem);
316 if (G_UNLIKELY (res == 0))
317 g_error ("%s: CloseHandle failed with error %d", __func__, GetLastError ());
320 MONO_PROFILER_API MonoSemTimedwaitRet
321 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags);
323 static inline int
324 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
326 return mono_os_sem_timedwait (sem, MONO_INFINITE_WAIT, flags) != 0 ? -1 : 0;
329 static inline void
330 mono_os_sem_post (MonoSemType *sem)
332 BOOL res;
334 res = ReleaseSemaphore (*sem, 1, NULL);
335 if (G_UNLIKELY (res == 0))
336 g_error ("%s: ReleaseSemaphore failed with error %d", __func__, GetLastError ());
339 #endif
341 #endif /* _MONO_SEMAPHORE_H_ */