3 * Definitions for generic semaphore usage
6 * Geoff Norton <gnorton@novell.com>
8 * (C) 2009 Novell, Inc.
11 #ifndef _MONO_SEMAPHORE_H_
12 #define _MONO_SEMAPHORE_H_
19 #ifdef HAVE_SYS_TIME_H
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>
34 #include <mono/utils/mono-os-wait.h>
37 #define MONO_HAS_SEMAPHORES 1
39 #define MONO_NSEC_PER_SEC (1000 * 1000 * 1000)
41 #define MONO_INFINITE_WAIT ((guint32) 0xFFFFFFFF)
44 MONO_SEM_FLAGS_NONE
= 0,
45 MONO_SEM_FLAGS_ALERTABLE
= 1 << 0,
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
;
59 mono_os_sem_init (MonoSemType
*sem
, int value
)
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
);
69 mono_os_sem_destroy (MonoSemType
*sem
)
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
);
79 mono_os_sem_wait (MonoSemType
*sem
, MonoSemFlags flags
)
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
))
91 return res
!= KERN_SUCCESS
? -1 : 0;
94 static inline MonoSemTimedwaitRet
95 mono_os_sem_timedwait (MonoSemType
*sem
, guint32 timeout_ms
, MonoSemFlags flags
)
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
;
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
);
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
)) {
125 resint
= gettimeofday (¤t
, 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) {
136 ts
.tv_nsec
+= MONO_NSEC_PER_SEC
;
149 return MONO_SEM_TIMEDWAIT_RET_SUCCESS
;
151 return MONO_SEM_TIMEDWAIT_RET_ALERTED
;
152 case KERN_OPERATION_TIMED_OUT
:
153 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT
;
155 g_assert_not_reached ();
160 mono_os_sem_post (MonoSemType
*sem
)
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
)
173 #elif !defined(HOST_WIN32) && defined(HAVE_SEMAPHORE_H)
175 typedef sem_t MonoSemType
;
178 mono_os_sem_init (MonoSemType
*sem
, int value
)
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
);
188 mono_os_sem_destroy (MonoSemType
*sem
)
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
);
198 mono_os_sem_wait (MonoSemType
*sem
, MonoSemFlags flags
)
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
))
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
;
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
);
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
;
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
;
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
)) {
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
;
268 g_assert_not_reached ();
272 mono_os_sem_post (MonoSemType
*sem
)
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
);
283 #include <mono/utils/mono-compiler.h>
285 typedef HANDLE MonoSemType
;
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
);
293 *sem
= CreateSemaphoreEx (NULL
, value
, 0x7FFFFFFF, NULL
, 0, SEMAPHORE_ALL_ACCESS
);
296 if (G_UNLIKELY (*sem
== NULL
))
297 g_error ("%s: CreateSemaphore failed with error %d", __func__
, GetLastError ());
301 mono_os_sem_destroy (MonoSemType
*sem
)
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
);
314 mono_os_sem_wait (MonoSemType
*sem
, MonoSemFlags flags
)
316 return mono_os_sem_timedwait (sem
, MONO_INFINITE_WAIT
, flags
) != 0 ? -1 : 0;
320 mono_os_sem_post (MonoSemType
*sem
)
324 res
= ReleaseSemaphore (*sem
, 1, NULL
);
325 if (G_UNLIKELY (res
== 0))
326 g_error ("%s: ReleaseSemaphore failed with error %d", __func__
, GetLastError ());
331 #endif /* _MONO_SEMAPHORE_H_ */