1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * Portability wrappers around POSIX Mutexes
6 * Authors: Jeffrey Stedfast <fejj@ximian.com>
8 * Copyright 2002 Ximian, Inc. (www.ximian.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13 #ifndef __MONO_OS_MUTEX_H__
14 #define __MONO_OS_MUTEX_H__
23 #if !defined(HOST_WIN32)
31 #ifdef HAVE_SYS_TIME_H
37 #ifndef MONO_INFINITE_WAIT
38 #define MONO_INFINITE_WAIT ((guint32) 0xFFFFFFFF)
42 #if !defined(HOST_WIN32)
44 typedef pthread_mutex_t mono_mutex_t;
45 typedef pthread_cond_t mono_cond_t;
48 mono_os_mutex_init (mono_mutex_t *mutex)
52 res = pthread_mutex_init (mutex, NULL);
53 if (G_UNLIKELY (res != 0))
54 g_error ("%s: pthread_mutex_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
58 mono_os_mutex_init_recursive (mono_mutex_t *mutex)
61 pthread_mutexattr_t attr;
63 res = pthread_mutexattr_init (&attr);
64 if (G_UNLIKELY (res != 0))
65 g_error ("%s: pthread_mutexattr_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
67 res = pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
68 if (G_UNLIKELY (res != 0))
69 g_error ("%s: pthread_mutexattr_settype failed with \"%s\" (%d)", __func__, g_strerror (res), res);
71 res = pthread_mutex_init (mutex, &attr);
72 if (G_UNLIKELY (res != 0))
73 g_error ("%s: pthread_mutex_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
75 res = pthread_mutexattr_destroy (&attr);
76 if (G_UNLIKELY (res != 0))
77 g_error ("%s: pthread_mutexattr_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
81 mono_os_mutex_destroy (mono_mutex_t *mutex)
85 res = pthread_mutex_destroy (mutex);
86 if (G_UNLIKELY (res != 0))
87 g_error ("%s: pthread_mutex_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
91 mono_os_mutex_lock (mono_mutex_t *mutex)
95 res = pthread_mutex_lock (mutex);
96 if (G_UNLIKELY (res != 0))
97 g_error ("%s: pthread_mutex_lock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
101 mono_os_mutex_trylock (mono_mutex_t *mutex)
105 res = pthread_mutex_trylock (mutex);
106 if (G_UNLIKELY (res != 0 && res != EBUSY))
107 g_error ("%s: pthread_mutex_trylock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
109 return res != 0 ? -1 : 0;
113 mono_os_mutex_unlock (mono_mutex_t *mutex)
117 res = pthread_mutex_unlock (mutex);
118 if (G_UNLIKELY (res != 0))
119 g_error ("%s: pthread_mutex_unlock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
123 mono_os_cond_init (mono_cond_t *cond)
127 #if !defined(CLOCK_MONOTONIC) || defined(PLATFORM_MACOSX)
128 res = pthread_cond_init (cond, NULL);
129 if (G_UNLIKELY (res != 0))
130 g_error ("%s: pthread_cond_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
132 /* POSIX standard does not compel to have CLOCK_MONOTONIC */
133 pthread_condattr_t attr;
135 res = pthread_condattr_init (&attr);
136 if (G_UNLIKELY (res != 0))
137 g_error ("%s: pthread_condattr_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
139 res = pthread_condattr_setclock (&attr, CLOCK_MONOTONIC);
140 if (G_UNLIKELY (res != 0))
141 g_error ("%s: pthread_condattr_setclock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
143 /* Attach an attribute having CLOCK_MONOTONIC to condition */
144 res = pthread_cond_init (cond, &attr);
145 if (G_UNLIKELY (res != 0))
146 g_error ("%s: pthread_cond_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
148 res = pthread_condattr_destroy (&attr);
149 if (G_UNLIKELY (res != 0))
150 g_error ("%s: pthread_condattr_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
155 mono_os_cond_destroy (mono_cond_t *cond)
159 res = pthread_cond_destroy (cond);
160 if (G_UNLIKELY (res != 0))
161 g_error ("%s: pthread_cond_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
165 mono_os_cond_wait (mono_cond_t *cond, mono_mutex_t *mutex)
169 res = pthread_cond_wait (cond, mutex);
170 if (G_UNLIKELY (res != 0))
171 g_error ("%s: pthread_cond_wait failed with \"%s\" (%d)", __func__, g_strerror (res), res);
175 mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ms)
177 #if !defined(CLOCK_MONOTONIC) || defined(PLATFORM_MACOSX)
183 if (timeout_ms == MONO_INFINITE_WAIT) {
184 mono_os_cond_wait (cond, mutex);
188 /* ms = 10^-3, us = 10^-6, ns = 10^-9 */
190 #if !defined(CLOCK_MONOTONIC) || defined(PLATFORM_MACOSX)
191 /* clock_gettime is not supported in MAC OS x */
192 res = gettimeofday (&tv, NULL);
193 if (G_UNLIKELY (res != 0))
194 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
196 ts.tv_sec = tv.tv_sec;
197 ts.tv_nsec = tv.tv_usec * 1000;
199 /* cond is using CLOCK_MONOTONIC as time source */
200 res = clock_gettime (CLOCK_MONOTONIC, &ts);
201 if (G_UNLIKELY (res != 0))
202 g_error ("%s: clock_gettime failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
205 ts.tv_sec += timeout_ms / 1000;
206 ts.tv_nsec += (timeout_ms % 1000) * 1000 * 1000;
207 if (ts.tv_nsec >= 1000 * 1000 * 1000) {
208 ts.tv_nsec -= 1000 * 1000 * 1000;
212 res = pthread_cond_timedwait (cond, mutex, &ts);
213 if (G_UNLIKELY (res != 0 && res != ETIMEDOUT))
214 g_error ("%s: pthread_cond_timedwait failed with \"%s\" (%d)", __func__, g_strerror (res), res);
216 return res != 0 ? -1 : 0;
220 mono_os_cond_signal (mono_cond_t *cond)
224 res = pthread_cond_signal (cond);
225 if (G_UNLIKELY (res != 0))
226 g_error ("%s: pthread_cond_signal failed with \"%s\" (%d)", __func__, g_strerror (res), res);
230 mono_os_cond_broadcast (mono_cond_t *cond)
234 res = pthread_cond_broadcast (cond);
235 if (G_UNLIKELY (res != 0))
236 g_error ("%s: pthread_cond_broadcast failed with \"%s\" (%d)", __func__, g_strerror (res), res);
241 /* Vanilla MinGW is missing some defs, load them from MinGW-w64. */
242 #if defined __MINGW32__ && !defined __MINGW64_VERSION_MAJOR && (_WIN32_WINNT >= 0x0600)
244 /* Fixme: Opaque structs */
245 typedef PVOID RTL_CONDITION_VARIABLE;
246 typedef PVOID RTL_SRWLOCK;
248 #ifndef _RTL_RUN_ONCE_DEF
249 #define _RTL_RUN_ONCE_DEF 1
250 typedef PVOID RTL_RUN_ONCE, *PRTL_RUN_ONCE;
251 typedef DWORD (WINAPI *PRTL_RUN_ONCE_INIT_FN)(PRTL_RUN_ONCE, PVOID, PVOID *);
252 #define RTL_RUN_ONCE_INIT 0
253 #define RTL_RUN_ONCE_CHECK_ONLY 1UL
254 #define RTL_RUN_ONCE_ASYNC 2UL
255 #define RTL_RUN_ONCE_INIT_FAILED 4UL
256 #define RTL_RUN_ONCE_CTX_RESERVED_BITS 2
257 #endif /* _RTL_RUN_ONCE_DEF */
258 #define RTL_SRWLOCK_INIT 0
259 #define RTL_CONDITION_VARIABLE_INIT 0
260 #define RTL_CONDITION_VARIABLE_LOCKMODE_SHARED 1
262 #define CONDITION_VARIABLE_INIT RTL_CONDITION_VARIABLE_INIT
263 #define CONDITION_VARIABLE_LOCKMODE_SHARED RTL_CONDITION_VARIABLE_LOCKMODE_SHARED
264 #define SRWLOCK_INIT RTL_SRWLOCK_INIT
266 /*Condition Variables http://msdn.microsoft.com/en-us/library/ms682052%28VS.85%29.aspx*/
267 typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE;
268 typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
270 WINBASEAPI VOID WINAPI InitializeConditionVariable(PCONDITION_VARIABLE ConditionVariable);
271 WINBASEAPI WINBOOL WINAPI SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable, PCRITICAL_SECTION CriticalSection, DWORD dwMilliseconds);
272 WINBASEAPI WINBOOL WINAPI SleepConditionVariableSRW(PCONDITION_VARIABLE ConditionVariable, PSRWLOCK SRWLock, DWORD dwMilliseconds, ULONG Flags);
273 WINBASEAPI VOID WINAPI WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable);
274 WINBASEAPI VOID WINAPI WakeConditionVariable(PCONDITION_VARIABLE ConditionVariable);
276 /*Slim Reader/Writer (SRW) Locks http://msdn.microsoft.com/en-us/library/aa904937%28VS.85%29.aspx*/
277 WINBASEAPI VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK SRWLock);
278 WINBASEAPI VOID WINAPI AcquireSRWLockShared(PSRWLOCK SRWLock);
279 WINBASEAPI VOID WINAPI InitializeSRWLock(PSRWLOCK SRWLock);
280 WINBASEAPI VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK SRWLock);
281 WINBASEAPI VOID WINAPI ReleaseSRWLockShared(PSRWLOCK SRWLock);
283 WINBASEAPI BOOLEAN TryAcquireSRWLockExclusive(PSRWLOCK SRWLock);
284 WINBASEAPI BOOLEAN TryAcquireSRWLockShared(PSRWLOCK SRWLock);
286 /*One-Time Initialization http://msdn.microsoft.com/en-us/library/aa363808(VS.85).aspx*/
287 #define INIT_ONCE_ASYNC 0x00000002UL
288 #define INIT_ONCE_INIT_FAILED 0x00000004UL
290 typedef PRTL_RUN_ONCE PINIT_ONCE;
291 typedef PRTL_RUN_ONCE LPINIT_ONCE;
292 typedef WINBOOL CALLBACK (*PINIT_ONCE_FN) (PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context);
294 WINBASEAPI WINBOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, LPVOID *lpContext);
295 WINBASEAPI WINBOOL WINAPI InitOnceComplete(LPINIT_ONCE lpInitOnce, DWORD dwFlags, LPVOID lpContext);
296 WINBASEAPI WINBOOL WINAPI InitOnceExecuteOnce(PINIT_ONCE InitOnce, PINIT_ONCE_FN InitFn, PVOID Parameter, LPVOID *Context);
298 /* https://msdn.microsoft.com/en-us/library/windows/desktop/ms683477(v=vs.85).aspx */
299 WINBASEAPI BOOL WINAPI InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags);
301 #define CRITICAL_SECTION_NO_DEBUG_INFO 0x01000000
303 #endif /* defined __MINGW32__ && !defined __MINGW64_VERSION_MAJOR && (_WIN32_WINNT >= 0x0600) */
305 typedef CRITICAL_SECTION mono_mutex_t;
306 typedef CONDITION_VARIABLE mono_cond_t;
309 mono_os_mutex_init (mono_mutex_t *mutex)
313 res = InitializeCriticalSectionEx (mutex, 0, CRITICAL_SECTION_NO_DEBUG_INFO);
314 if (G_UNLIKELY (res == 0))
315 g_error ("%s: InitializeCriticalSectionEx failed with error %d", __func__, GetLastError ());
319 mono_os_mutex_init_recursive (mono_mutex_t *mutex)
323 res = InitializeCriticalSectionEx (mutex, 0, CRITICAL_SECTION_NO_DEBUG_INFO);
324 if (G_UNLIKELY (res == 0))
325 g_error ("%s: InitializeCriticalSectionEx failed with error %d", __func__, GetLastError ());
329 mono_os_mutex_destroy (mono_mutex_t *mutex)
331 DeleteCriticalSection (mutex);
335 mono_os_mutex_lock (mono_mutex_t *mutex)
337 EnterCriticalSection (mutex);
341 mono_os_mutex_trylock (mono_mutex_t *mutex)
343 return TryEnterCriticalSection (mutex) == 0 ? -1 : 0;
347 mono_os_mutex_unlock (mono_mutex_t *mutex)
349 LeaveCriticalSection (mutex);
353 mono_os_cond_init (mono_cond_t *cond)
355 InitializeConditionVariable (cond);
359 mono_os_cond_destroy (mono_cond_t *cond)
361 /* Beauty of win32 API: do not destroy it */
365 mono_os_cond_wait (mono_cond_t *cond, mono_mutex_t *mutex)
369 res = SleepConditionVariableCS (cond, mutex, INFINITE);
370 if (G_UNLIKELY (res == 0))
371 g_error ("%s: SleepConditionVariableCS failed with error %d", __func__, GetLastError ());
375 mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ms)
379 res = SleepConditionVariableCS (cond, mutex, timeout_ms);
380 if (G_UNLIKELY (res == 0 && GetLastError () != ERROR_TIMEOUT))
381 g_error ("%s: SleepConditionVariableCS failed with error %d", __func__, GetLastError ());
383 return res == 0 ? -1 : 0;
387 mono_os_cond_signal (mono_cond_t *cond)
389 WakeConditionVariable (cond);
393 mono_os_cond_broadcast (mono_cond_t *cond)
395 WakeAllConditionVariable (cond);
402 #endif /* __MONO_OS_MUTEX_H__ */