1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * mono-os-mutex.h: Portability wrappers around POSIX Mutexes
5 * Authors: Jeffrey Stedfast <fejj@ximian.com>
7 * Copyright 2002 Ximian, Inc. (www.ximian.com)
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12 #ifndef __MONO_OS_MUTEX_H__
13 #define __MONO_OS_MUTEX_H__
22 #if !defined(HOST_WIN32)
30 #ifdef HAVE_SYS_TIME_H
36 #ifndef MONO_INFINITE_WAIT
37 #define MONO_INFINITE_WAIT ((guint32) 0xFFFFFFFF)
41 #if !defined(HOST_WIN32)
43 typedef pthread_mutex_t mono_mutex_t;
44 typedef pthread_cond_t mono_cond_t;
47 mono_os_mutex_init (mono_mutex_t *mutex)
51 res = pthread_mutex_init (mutex, NULL);
52 if (G_UNLIKELY (res != 0))
53 g_error ("%s: pthread_mutex_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
57 mono_os_mutex_init_recursive (mono_mutex_t *mutex)
60 pthread_mutexattr_t attr;
62 res = pthread_mutexattr_init (&attr);
63 if (G_UNLIKELY (res != 0))
64 g_error ("%s: pthread_mutexattr_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
66 res = pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
67 if (G_UNLIKELY (res != 0))
68 g_error ("%s: pthread_mutexattr_settype failed with \"%s\" (%d)", __func__, g_strerror (res), res);
70 res = pthread_mutex_init (mutex, &attr);
71 if (G_UNLIKELY (res != 0))
72 g_error ("%s: pthread_mutex_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
74 res = pthread_mutexattr_destroy (&attr);
75 if (G_UNLIKELY (res != 0))
76 g_error ("%s: pthread_mutexattr_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
80 mono_os_mutex_destroy (mono_mutex_t *mutex)
84 res = pthread_mutex_destroy (mutex);
85 if (G_UNLIKELY (res != 0))
86 g_error ("%s: pthread_mutex_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
90 mono_os_mutex_lock (mono_mutex_t *mutex)
94 res = pthread_mutex_lock (mutex);
95 if (G_UNLIKELY (res != 0))
96 g_error ("%s: pthread_mutex_lock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
100 mono_os_mutex_trylock (mono_mutex_t *mutex)
104 res = pthread_mutex_trylock (mutex);
105 if (G_UNLIKELY (res != 0 && res != EBUSY))
106 g_error ("%s: pthread_mutex_trylock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
108 return res != 0 ? -1 : 0;
112 mono_os_mutex_unlock (mono_mutex_t *mutex)
116 res = pthread_mutex_unlock (mutex);
117 if (G_UNLIKELY (res != 0))
118 g_error ("%s: pthread_mutex_unlock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
122 mono_os_cond_init (mono_cond_t *cond)
126 #if !defined(CLOCK_MONOTONIC) || defined(PLATFORM_MACOSX)
127 res = pthread_cond_init (cond, NULL);
128 if (G_UNLIKELY (res != 0))
129 g_error ("%s: pthread_cond_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
131 /* POSIX standard does not compel to have CLOCK_MONOTONIC */
132 pthread_condattr_t attr;
134 res = pthread_condattr_init (&attr);
135 if (G_UNLIKELY (res != 0))
136 g_error ("%s: pthread_condattr_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
138 res = pthread_condattr_setclock (&attr, CLOCK_MONOTONIC);
139 if (G_UNLIKELY (res != 0))
140 g_error ("%s: pthread_condattr_setclock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
142 /* Attach an attribute having CLOCK_MONOTONIC to condition */
143 res = pthread_cond_init (cond, &attr);
144 if (G_UNLIKELY (res != 0))
145 g_error ("%s: pthread_cond_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
147 res = pthread_condattr_destroy (&attr);
148 if (G_UNLIKELY (res != 0))
149 g_error ("%s: pthread_condattr_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
154 mono_os_cond_destroy (mono_cond_t *cond)
158 res = pthread_cond_destroy (cond);
159 if (G_UNLIKELY (res != 0))
160 g_error ("%s: pthread_cond_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
164 mono_os_cond_wait (mono_cond_t *cond, mono_mutex_t *mutex)
168 res = pthread_cond_wait (cond, mutex);
169 if (G_UNLIKELY (res != 0))
170 g_error ("%s: pthread_cond_wait failed with \"%s\" (%d)", __func__, g_strerror (res), res);
174 mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ms)
176 #if !defined(CLOCK_MONOTONIC) || defined(PLATFORM_MACOSX)
182 if (timeout_ms == MONO_INFINITE_WAIT) {
183 mono_os_cond_wait (cond, mutex);
187 /* ms = 10^-3, us = 10^-6, ns = 10^-9 */
189 #if !defined(CLOCK_MONOTONIC) || defined(PLATFORM_MACOSX)
190 /* clock_gettime is not supported in MAC OS x */
191 res = gettimeofday (&tv, NULL);
192 if (G_UNLIKELY (res != 0))
193 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
195 ts.tv_sec = tv.tv_sec;
196 ts.tv_nsec = tv.tv_usec * 1000;
198 /* cond is using CLOCK_MONOTONIC as time source */
199 res = clock_gettime (CLOCK_MONOTONIC, &ts);
200 if (G_UNLIKELY (res != 0))
201 g_error ("%s: clock_gettime failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
204 ts.tv_sec += timeout_ms / 1000;
205 ts.tv_nsec += (timeout_ms % 1000) * 1000 * 1000;
206 if (ts.tv_nsec >= 1000 * 1000 * 1000) {
207 ts.tv_nsec -= 1000 * 1000 * 1000;
211 res = pthread_cond_timedwait (cond, mutex, &ts);
212 if (G_UNLIKELY (res != 0 && res != ETIMEDOUT))
213 g_error ("%s: pthread_cond_timedwait failed with \"%s\" (%d)", __func__, g_strerror (res), res);
215 return res != 0 ? -1 : 0;
219 mono_os_cond_signal (mono_cond_t *cond)
223 res = pthread_cond_signal (cond);
224 if (G_UNLIKELY (res != 0))
225 g_error ("%s: pthread_cond_signal failed with \"%s\" (%d)", __func__, g_strerror (res), res);
229 mono_os_cond_broadcast (mono_cond_t *cond)
233 res = pthread_cond_broadcast (cond);
234 if (G_UNLIKELY (res != 0))
235 g_error ("%s: pthread_cond_broadcast failed with \"%s\" (%d)", __func__, g_strerror (res), res);
240 /* Vanilla MinGW is missing some defs, load them from MinGW-w64. */
241 #if defined __MINGW32__ && !defined __MINGW64_VERSION_MAJOR && (_WIN32_WINNT >= 0x0600)
243 /* Fixme: Opaque structs */
244 typedef PVOID RTL_CONDITION_VARIABLE;
245 typedef PVOID RTL_SRWLOCK;
247 #ifndef _RTL_RUN_ONCE_DEF
248 #define _RTL_RUN_ONCE_DEF 1
249 typedef PVOID RTL_RUN_ONCE, *PRTL_RUN_ONCE;
250 typedef DWORD (WINAPI *PRTL_RUN_ONCE_INIT_FN)(PRTL_RUN_ONCE, PVOID, PVOID *);
251 #define RTL_RUN_ONCE_INIT 0
252 #define RTL_RUN_ONCE_CHECK_ONLY 1UL
253 #define RTL_RUN_ONCE_ASYNC 2UL
254 #define RTL_RUN_ONCE_INIT_FAILED 4UL
255 #define RTL_RUN_ONCE_CTX_RESERVED_BITS 2
256 #endif /* _RTL_RUN_ONCE_DEF */
257 #define RTL_SRWLOCK_INIT 0
258 #define RTL_CONDITION_VARIABLE_INIT 0
259 #define RTL_CONDITION_VARIABLE_LOCKMODE_SHARED 1
261 #define CONDITION_VARIABLE_INIT RTL_CONDITION_VARIABLE_INIT
262 #define CONDITION_VARIABLE_LOCKMODE_SHARED RTL_CONDITION_VARIABLE_LOCKMODE_SHARED
263 #define SRWLOCK_INIT RTL_SRWLOCK_INIT
265 /*Condition Variables http://msdn.microsoft.com/en-us/library/ms682052%28VS.85%29.aspx*/
266 typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE;
267 typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
269 WINBASEAPI VOID WINAPI InitializeConditionVariable(PCONDITION_VARIABLE ConditionVariable);
270 WINBASEAPI WINBOOL WINAPI SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable, PCRITICAL_SECTION CriticalSection, DWORD dwMilliseconds);
271 WINBASEAPI WINBOOL WINAPI SleepConditionVariableSRW(PCONDITION_VARIABLE ConditionVariable, PSRWLOCK SRWLock, DWORD dwMilliseconds, ULONG Flags);
272 WINBASEAPI VOID WINAPI WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable);
273 WINBASEAPI VOID WINAPI WakeConditionVariable(PCONDITION_VARIABLE ConditionVariable);
275 /*Slim Reader/Writer (SRW) Locks http://msdn.microsoft.com/en-us/library/aa904937%28VS.85%29.aspx*/
276 WINBASEAPI VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK SRWLock);
277 WINBASEAPI VOID WINAPI AcquireSRWLockShared(PSRWLOCK SRWLock);
278 WINBASEAPI VOID WINAPI InitializeSRWLock(PSRWLOCK SRWLock);
279 WINBASEAPI VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK SRWLock);
280 WINBASEAPI VOID WINAPI ReleaseSRWLockShared(PSRWLOCK SRWLock);
282 WINBASEAPI BOOLEAN TryAcquireSRWLockExclusive(PSRWLOCK SRWLock);
283 WINBASEAPI BOOLEAN TryAcquireSRWLockShared(PSRWLOCK SRWLock);
285 /*One-Time Initialization http://msdn.microsoft.com/en-us/library/aa363808(VS.85).aspx*/
286 #define INIT_ONCE_ASYNC 0x00000002UL
287 #define INIT_ONCE_INIT_FAILED 0x00000004UL
289 typedef PRTL_RUN_ONCE PINIT_ONCE;
290 typedef PRTL_RUN_ONCE LPINIT_ONCE;
291 typedef WINBOOL CALLBACK (*PINIT_ONCE_FN) (PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context);
293 WINBASEAPI WINBOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, LPVOID *lpContext);
294 WINBASEAPI WINBOOL WINAPI InitOnceComplete(LPINIT_ONCE lpInitOnce, DWORD dwFlags, LPVOID lpContext);
295 WINBASEAPI WINBOOL WINAPI InitOnceExecuteOnce(PINIT_ONCE InitOnce, PINIT_ONCE_FN InitFn, PVOID Parameter, LPVOID *Context);
297 /* https://msdn.microsoft.com/en-us/library/windows/desktop/ms683477(v=vs.85).aspx */
298 WINBASEAPI BOOL WINAPI InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags);
300 #define CRITICAL_SECTION_NO_DEBUG_INFO 0x01000000
302 #endif /* defined __MINGW32__ && !defined __MINGW64_VERSION_MAJOR && (_WIN32_WINNT >= 0x0600) */
304 typedef CRITICAL_SECTION mono_mutex_t;
305 typedef CONDITION_VARIABLE mono_cond_t;
308 mono_os_mutex_init (mono_mutex_t *mutex)
312 res = InitializeCriticalSectionEx (mutex, 0, CRITICAL_SECTION_NO_DEBUG_INFO);
313 if (G_UNLIKELY (res == 0))
314 g_error ("%s: InitializeCriticalSectionEx failed with error %d", __func__, GetLastError ());
318 mono_os_mutex_init_recursive (mono_mutex_t *mutex)
322 res = InitializeCriticalSectionEx (mutex, 0, CRITICAL_SECTION_NO_DEBUG_INFO);
323 if (G_UNLIKELY (res == 0))
324 g_error ("%s: InitializeCriticalSectionEx failed with error %d", __func__, GetLastError ());
328 mono_os_mutex_destroy (mono_mutex_t *mutex)
330 DeleteCriticalSection (mutex);
334 mono_os_mutex_lock (mono_mutex_t *mutex)
336 EnterCriticalSection (mutex);
340 mono_os_mutex_trylock (mono_mutex_t *mutex)
342 return TryEnterCriticalSection (mutex) == 0 ? -1 : 0;
346 mono_os_mutex_unlock (mono_mutex_t *mutex)
348 LeaveCriticalSection (mutex);
352 mono_os_cond_init (mono_cond_t *cond)
354 InitializeConditionVariable (cond);
358 mono_os_cond_destroy (mono_cond_t *cond)
360 /* Beauty of win32 API: do not destroy it */
364 mono_os_cond_wait (mono_cond_t *cond, mono_mutex_t *mutex)
368 res = SleepConditionVariableCS (cond, mutex, INFINITE);
369 if (G_UNLIKELY (res == 0))
370 g_error ("%s: SleepConditionVariableCS failed with error %d", __func__, GetLastError ());
374 mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ms)
378 res = SleepConditionVariableCS (cond, mutex, timeout_ms);
379 if (G_UNLIKELY (res == 0 && GetLastError () != ERROR_TIMEOUT))
380 g_error ("%s: SleepConditionVariableCS failed with error %d", __func__, GetLastError ());
382 return res == 0 ? -1 : 0;
386 mono_os_cond_signal (mono_cond_t *cond)
388 WakeConditionVariable (cond);
392 mono_os_cond_broadcast (mono_cond_t *cond)
394 WakeAllConditionVariable (cond);
401 #endif /* __MONO_OS_MUTEX_H__ */