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>
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)
45 MONO_SEM_FLAGS_NONE
= 0,
46 MONO_SEM_FLAGS_ALERTABLE
= 1 << 0,
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
;
60 mono_os_sem_init (MonoSemType
*sem
, int value
)
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
);
70 mono_os_sem_destroy (MonoSemType
*sem
)
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
);
80 mono_os_sem_wait (MonoSemType
*sem
, MonoSemFlags flags
)
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
))
92 return res
!= KERN_SUCCESS
? -1 : 0;
95 static inline MonoSemTimedwaitRet
96 mono_os_sem_timedwait (MonoSemType
*sem
, guint32 timeout_ms
, MonoSemFlags flags
)
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
;
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
);
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
)) {
126 resint
= gettimeofday (¤t
, 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) {
137 ts
.tv_nsec
+= MONO_NSEC_PER_SEC
;
150 return MONO_SEM_TIMEDWAIT_RET_SUCCESS
;
152 return MONO_SEM_TIMEDWAIT_RET_ALERTED
;
153 case KERN_OPERATION_TIMED_OUT
:
154 return MONO_SEM_TIMEDWAIT_RET_TIMEDOUT
;
156 g_assert_not_reached ();
161 mono_os_sem_post (MonoSemType
*sem
)
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
)
174 #elif !defined(HOST_WIN32) && defined(HAVE_SEMAPHORE_H)
176 typedef sem_t MonoSemType
;
179 mono_os_sem_init (MonoSemType
*sem
, int value
)
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
);
189 mono_os_sem_destroy (MonoSemType
*sem
)
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
);
199 mono_os_sem_wait (MonoSemType
*sem
, MonoSemFlags flags
)
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
))
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
;
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
);
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
;
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
;
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
)) {
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
;
269 g_assert_not_reached ();
273 mono_os_sem_post (MonoSemType
*sem
)
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
);
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
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
);
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
302 mono_os_sem_init (MonoSemType
*sem
, int value
)
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 */
311 mono_os_sem_destroy (MonoSemType
*sem
)
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
);
324 mono_os_sem_wait (MonoSemType
*sem
, MonoSemFlags flags
)
326 return mono_os_sem_timedwait (sem
, MONO_INFINITE_WAIT
, flags
) != 0 ? -1 : 0;
330 mono_os_sem_post (MonoSemType
*sem
)
334 res
= ReleaseSemaphore (*sem
, 1, NULL
);
335 if (G_UNLIKELY (res
== 0))
336 g_error ("%s: ReleaseSemaphore failed with error %d", __func__
, GetLastError ());
341 #endif /* _MONO_SEMAPHORE_H_ */