[Facades] Add netstandard
[mono-project.git] / mono / utils / mono-os-semaphore.h
blobc4bfe620f98edd116b07884e10c0f9b5ecae0922
1 /*
2 * mono-os-semaphore.h: Definitions for generic semaphore usage
4 * Author:
5 * Geoff Norton <gnorton@novell.com>
7 * (C) 2009 Novell, Inc.
8 */
10 #ifndef _MONO_SEMAPHORE_H_
11 #define _MONO_SEMAPHORE_H_
13 #include <config.h>
14 #include <glib.h>
16 #include <errno.h>
18 #ifdef HAVE_SYS_TIME_H
19 #include <sys/time.h>
20 #endif
22 #ifdef HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif
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>
32 #else
33 #include <winsock2.h>
34 #include <windows.h>
35 #endif
37 #define MONO_HAS_SEMAPHORES 1
39 #ifndef NSEC_PER_SEC
40 #define NSEC_PER_SEC (1000 * 1000 * 1000)
41 #endif
43 #ifndef MONO_INFINITE_WAIT
44 #define MONO_INFINITE_WAIT ((guint32) 0xFFFFFFFF)
45 #endif
47 G_BEGIN_DECLS
49 typedef enum {
50 MONO_SEM_FLAGS_NONE = 0,
51 MONO_SEM_FLAGS_ALERTABLE = 1 << 0,
52 } MonoSemFlags;
54 typedef enum {
55 MONO_SEM_TIMEDWAIT_RET_SUCCESS = 0,
56 MONO_SEM_TIMEDWAIT_RET_ALERTED = -1,
57 MONO_SEM_TIMEDWAIT_RET_TIMEDOUT = -2,
58 } MonoSemTimedwaitRet;
60 #if defined(USE_MACH_SEMA)
62 typedef semaphore_t MonoSemType;
64 static inline void
65 mono_os_sem_init (MonoSemType *sem, int value)
67 kern_return_t res;
69 res = semaphore_create (current_task (), sem, SYNC_POLICY_FIFO, value);
70 if (G_UNLIKELY (res != KERN_SUCCESS))
71 g_error ("%s: semaphore_create failed with error %d", __func__, res);
74 static inline void
75 mono_os_sem_destroy (MonoSemType *sem)
77 kern_return_t res;
79 res = semaphore_destroy (current_task (), *sem);
80 if (G_UNLIKELY (res != KERN_SUCCESS))
81 g_error ("%s: semaphore_destroy failed with error %d", __func__, res);
84 static inline int
85 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
87 kern_return_t res;
89 retry:
90 res = semaphore_wait (*sem);
91 if (G_UNLIKELY (res != KERN_SUCCESS && res != KERN_ABORTED))
92 g_error ("%s: semaphore_wait failed with error %d", __func__, res);
94 if (res == KERN_ABORTED && !(flags & MONO_SEM_FLAGS_ALERTABLE))
95 goto retry;
97 return res != KERN_SUCCESS ? -1 : 0;
100 static inline MonoSemTimedwaitRet
101 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
103 kern_return_t res;
104 int resint;
105 mach_timespec_t ts, copy;
106 struct timeval start, current;
108 if (timeout_ms == MONO_INFINITE_WAIT)
109 return (MonoSemTimedwaitRet) mono_os_sem_wait (sem, flags);
111 ts.tv_sec = timeout_ms / 1000;
112 ts.tv_nsec = (timeout_ms % 1000) * 1000000;
113 while (ts.tv_nsec >= NSEC_PER_SEC) {
114 ts.tv_nsec -= NSEC_PER_SEC;
115 ts.tv_sec++;
118 copy = ts;
119 resint = gettimeofday (&start, NULL);
120 if (G_UNLIKELY (resint != 0))
121 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
123 retry:
124 res = semaphore_timedwait (*sem, ts);
125 if (G_UNLIKELY (res != KERN_SUCCESS && res != KERN_ABORTED && res != KERN_OPERATION_TIMED_OUT))
126 g_error ("%s: semaphore_timedwait failed with error %d", __func__, res);
128 if (res == KERN_ABORTED && !(flags & MONO_SEM_FLAGS_ALERTABLE)) {
129 ts = copy;
131 resint = gettimeofday (&current, NULL);
132 if (G_UNLIKELY (resint != 0))
133 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
135 ts.tv_sec -= (current.tv_sec - start.tv_sec);
136 ts.tv_nsec -= (current.tv_usec - start.tv_usec) * 1000;
137 if (ts.tv_nsec < 0) {
138 if (ts.tv_sec <= 0) {
139 ts.tv_nsec = 0;
140 } else {
141 ts.tv_sec--;
142 ts.tv_nsec += NSEC_PER_SEC;
145 if (ts.tv_sec < 0) {
146 ts.tv_sec = 0;
147 ts.tv_nsec = 0;
150 goto retry;
153 switch (res) {
154 case KERN_SUCCESS:
155 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
156 case KERN_ABORTED:
157 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
158 case KERN_OPERATION_TIMED_OUT:
159 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
160 default:
161 g_assert_not_reached ();
165 static inline void
166 mono_os_sem_post (MonoSemType *sem)
168 kern_return_t res;
170 retry:
171 res = semaphore_signal (*sem);
172 if (G_UNLIKELY (res != KERN_SUCCESS && res != KERN_ABORTED))
173 g_error ("%s: semaphore_signal failed with error %d", __func__, res);
175 if (res == KERN_ABORTED)
176 goto retry;
179 #elif !defined(HOST_WIN32) && defined(HAVE_SEMAPHORE_H)
181 typedef sem_t MonoSemType;
183 static inline void
184 mono_os_sem_init (MonoSemType *sem, int value)
186 int res;
188 res = sem_init (sem, 0, value);
189 if (G_UNLIKELY (res != 0))
190 g_error ("%s: sem_init failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
193 static inline void
194 mono_os_sem_destroy (MonoSemType *sem)
196 int res;
198 res = sem_destroy (sem);
199 if (G_UNLIKELY (res != 0))
200 g_error ("%s: sem_destroy failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
203 static inline int
204 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
206 int res;
208 retry:
209 res = sem_wait (sem);
210 if (G_UNLIKELY (res != 0 && errno != EINTR))
211 g_error ("%s: sem_wait failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
213 if (res != 0 && errno == EINTR && !(flags & MONO_SEM_FLAGS_ALERTABLE))
214 goto retry;
216 return res != 0 ? -1 : 0;
219 static inline MonoSemTimedwaitRet
220 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
222 struct timespec ts, copy;
223 struct timeval t;
224 int res;
226 if (timeout_ms == 0) {
227 res = sem_trywait (sem);
228 if (G_UNLIKELY (res != 0 && errno != EINTR && errno != EAGAIN))
229 g_error ("%s: sem_trywait failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
231 if (res == 0)
232 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
233 else if (errno == EINTR)
234 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
235 else if (errno == EAGAIN)
236 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
237 else
238 g_assert_not_reached ();
241 if (timeout_ms == MONO_INFINITE_WAIT)
242 return (MonoSemTimedwaitRet) mono_os_sem_wait (sem, flags);
244 res = gettimeofday (&t, NULL);
245 if (G_UNLIKELY (res != 0))
246 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
248 ts.tv_sec = timeout_ms / 1000 + t.tv_sec;
249 ts.tv_nsec = (timeout_ms % 1000) * 1000000 + t.tv_usec * 1000;
250 while (ts.tv_nsec >= NSEC_PER_SEC) {
251 ts.tv_nsec -= NSEC_PER_SEC;
252 ts.tv_sec++;
255 copy = ts;
257 retry:
258 res = sem_timedwait (sem, &ts);
259 if (G_UNLIKELY (res != 0 && errno != EINTR && errno != ETIMEDOUT))
260 g_error ("%s: sem_timedwait failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
262 if (res != 0 && errno == EINTR && !(flags & MONO_SEM_FLAGS_ALERTABLE)) {
263 ts = copy;
264 goto retry;
267 if (res == 0)
268 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
269 else if (errno == EINTR)
270 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
271 else if (errno == ETIMEDOUT)
272 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
273 else
274 g_assert_not_reached ();
277 static inline void
278 mono_os_sem_post (MonoSemType *sem)
280 int res;
282 res = sem_post (sem);
283 if (G_UNLIKELY (res != 0))
284 g_error ("%s: sem_post failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
287 #else
289 typedef HANDLE MonoSemType;
291 static inline void
292 mono_os_sem_init (MonoSemType *sem, int value)
294 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
295 *sem = CreateSemaphore (NULL, value, 0x7FFFFFFF, NULL);
296 #else
297 *sem = CreateSemaphoreEx (NULL, value, 0x7FFFFFFF, NULL, 0, SEMAPHORE_ALL_ACCESS);
298 #endif
300 if (G_UNLIKELY (*sem == NULL))
301 g_error ("%s: CreateSemaphore failed with error %d", __func__, GetLastError ());
304 static inline void
305 mono_os_sem_destroy (MonoSemType *sem)
307 BOOL res;
309 res = CloseHandle (*sem);
310 if (G_UNLIKELY (res == 0))
311 g_error ("%s: CloseHandle failed with error %d", __func__, GetLastError ());
314 static inline MonoSemTimedwaitRet
315 mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
317 BOOL res;
319 retry:
320 res = WaitForSingleObjectEx (*sem, timeout_ms, flags & MONO_SEM_FLAGS_ALERTABLE);
321 if (G_UNLIKELY (res != WAIT_OBJECT_0 && res != WAIT_IO_COMPLETION && res != WAIT_TIMEOUT))
322 g_error ("%s: WaitForSingleObjectEx failed with error %d", __func__, GetLastError ());
324 if (res == WAIT_IO_COMPLETION && !(flags & MONO_SEM_FLAGS_ALERTABLE))
325 goto retry;
327 switch (res) {
328 case WAIT_OBJECT_0:
329 return MONO_SEM_TIMEDWAIT_RET_SUCCESS;
330 case WAIT_IO_COMPLETION:
331 return MONO_SEM_TIMEDWAIT_RET_ALERTED;
332 case WAIT_TIMEOUT:
333 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT;
334 default:
335 g_assert_not_reached ();
339 static inline int
340 mono_os_sem_wait (MonoSemType *sem, MonoSemFlags flags)
342 return mono_os_sem_timedwait (sem, INFINITE, flags) != 0 ? -1 : 0;
345 static inline void
346 mono_os_sem_post (MonoSemType *sem)
348 BOOL res;
350 res = ReleaseSemaphore (*sem, 1, NULL);
351 if (G_UNLIKELY (res == 0))
352 g_error ("%s: ReleaseSemaphore failed with error %d", __func__, GetLastError ());
355 #endif
357 G_END_DECLS
359 #endif /* _MONO_SEMAPHORE_H_ */