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,
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
;
65 mono_os_sem_init (MonoSemType
*sem
, int value
)
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
);
75 mono_os_sem_destroy (MonoSemType
*sem
)
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
);
85 mono_os_sem_wait (MonoSemType
*sem
, MonoSemFlags flags
)
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
))
97 return res
!= KERN_SUCCESS
? -1 : 0;
100 static inline MonoSemTimedwaitRet
101 mono_os_sem_timedwait (MonoSemType
*sem
, guint32 timeout_ms
, MonoSemFlags flags
)
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
;
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
);
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
)) {
131 resint
= gettimeofday (¤t
, 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) {
142 ts
.tv_nsec
+= NSEC_PER_SEC
;
155 return MONO_SEM_TIMEDWAIT_RET_SUCCESS
;
157 return MONO_SEM_TIMEDWAIT_RET_ALERTED
;
158 case KERN_OPERATION_TIMED_OUT
:
159 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT
;
161 g_assert_not_reached ();
166 mono_os_sem_post (MonoSemType
*sem
)
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
)
179 #elif !defined(HOST_WIN32) && defined(HAVE_SEMAPHORE_H)
181 typedef sem_t MonoSemType
;
184 mono_os_sem_init (MonoSemType
*sem
, int value
)
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
);
194 mono_os_sem_destroy (MonoSemType
*sem
)
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
);
204 mono_os_sem_wait (MonoSemType
*sem
, MonoSemFlags flags
)
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
))
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
;
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
);
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
;
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
;
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
)) {
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
;
274 g_assert_not_reached ();
278 mono_os_sem_post (MonoSemType
*sem
)
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
);
289 typedef HANDLE MonoSemType
;
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
);
297 *sem
= CreateSemaphoreEx (NULL
, value
, 0x7FFFFFFF, NULL
, 0, SEMAPHORE_ALL_ACCESS
);
300 if (G_UNLIKELY (*sem
== NULL
))
301 g_error ("%s: CreateSemaphore failed with error %d", __func__
, GetLastError ());
305 mono_os_sem_destroy (MonoSemType
*sem
)
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
)
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
))
329 return MONO_SEM_TIMEDWAIT_RET_SUCCESS
;
330 case WAIT_IO_COMPLETION
:
331 return MONO_SEM_TIMEDWAIT_RET_ALERTED
;
333 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT
;
335 g_assert_not_reached ();
340 mono_os_sem_wait (MonoSemType
*sem
, MonoSemFlags flags
)
342 return mono_os_sem_timedwait (sem
, INFINITE
, flags
) != 0 ? -1 : 0;
346 mono_os_sem_post (MonoSemType
*sem
)
350 res
= ReleaseSemaphore (*sem
, 1, NULL
);
351 if (G_UNLIKELY (res
== 0))
352 g_error ("%s: ReleaseSemaphore failed with error %d", __func__
, GetLastError ());
359 #endif /* _MONO_SEMAPHORE_H_ */