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 && res != EBUSY))
86 g_error ("%s: pthread_mutex_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
88 return res != 0 ? -1 : 0;
92 mono_os_mutex_lock (mono_mutex_t *mutex)
96 res = pthread_mutex_lock (mutex);
97 if (G_UNLIKELY (res != 0))
98 g_error ("%s: pthread_mutex_lock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
102 mono_os_mutex_trylock (mono_mutex_t *mutex)
106 res = pthread_mutex_trylock (mutex);
107 if (G_UNLIKELY (res != 0 && res != EBUSY))
108 g_error ("%s: pthread_mutex_trylock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
110 return res != 0 ? -1 : 0;
114 mono_os_mutex_unlock (mono_mutex_t *mutex)
118 res = pthread_mutex_unlock (mutex);
119 if (G_UNLIKELY (res != 0))
120 g_error ("%s: pthread_mutex_unlock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
124 mono_os_cond_init (mono_cond_t *cond)
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);
134 mono_os_cond_destroy (mono_cond_t *cond)
138 res = pthread_cond_destroy (cond);
139 if (G_UNLIKELY (res != 0 && res != EBUSY))
140 g_error ("%s: pthread_cond_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
142 return res != 0 ? -1 : 0;
146 mono_os_cond_wait (mono_cond_t *cond, mono_mutex_t *mutex)
150 res = pthread_cond_wait (cond, mutex);
151 if (G_UNLIKELY (res != 0))
152 g_error ("%s: pthread_cond_wait failed with \"%s\" (%d)", __func__, g_strerror (res), res);
156 mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ms)
163 if (timeout_ms == MONO_INFINITE_WAIT) {
164 mono_os_cond_wait (cond, mutex);
168 /* ms = 10^-3, us = 10^-6, ns = 10^-9 */
170 res = gettimeofday (&tv, NULL);
171 if (G_UNLIKELY (res != 0))
172 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
174 tv.tv_sec += timeout_ms / 1000;
175 usecs = tv.tv_usec + ((timeout_ms % 1000) * 1000);
176 if (usecs >= 1000000) {
180 ts.tv_sec = tv.tv_sec;
181 ts.tv_nsec = usecs * 1000;
183 res = pthread_cond_timedwait (cond, mutex, &ts);
184 if (G_UNLIKELY (res != 0 && res != ETIMEDOUT))
185 g_error ("%s: pthread_cond_timedwait failed with \"%s\" (%d)", __func__, g_strerror (res), res);
187 return res != 0 ? -1 : 0;
191 mono_os_cond_signal (mono_cond_t *cond)
195 res = pthread_cond_signal (cond);
196 if (G_UNLIKELY (res != 0))
197 g_error ("%s: pthread_cond_signal failed with \"%s\" (%d)", __func__, g_strerror (res), res);
201 mono_os_cond_broadcast (mono_cond_t *cond)
205 res = pthread_cond_broadcast (cond);
206 if (G_UNLIKELY (res != 0))
207 g_error ("%s: pthread_cond_broadcast failed with \"%s\" (%d)", __func__, g_strerror (res), res);
212 /* Vanilla MinGW is missing some defs, load them from MinGW-w64. */
213 #if defined __MINGW32__ && !defined __MINGW64_VERSION_MAJOR && (_WIN32_WINNT >= 0x0600)
215 /* Fixme: Opaque structs */
216 typedef PVOID RTL_CONDITION_VARIABLE;
217 typedef PVOID RTL_SRWLOCK;
219 #ifndef _RTL_RUN_ONCE_DEF
220 #define _RTL_RUN_ONCE_DEF 1
221 typedef PVOID RTL_RUN_ONCE, *PRTL_RUN_ONCE;
222 typedef DWORD (WINAPI *PRTL_RUN_ONCE_INIT_FN)(PRTL_RUN_ONCE, PVOID, PVOID *);
223 #define RTL_RUN_ONCE_INIT 0
224 #define RTL_RUN_ONCE_CHECK_ONLY 1UL
225 #define RTL_RUN_ONCE_ASYNC 2UL
226 #define RTL_RUN_ONCE_INIT_FAILED 4UL
227 #define RTL_RUN_ONCE_CTX_RESERVED_BITS 2
228 #endif /* _RTL_RUN_ONCE_DEF */
229 #define RTL_SRWLOCK_INIT 0
230 #define RTL_CONDITION_VARIABLE_INIT 0
231 #define RTL_CONDITION_VARIABLE_LOCKMODE_SHARED 1
233 #define CONDITION_VARIABLE_INIT RTL_CONDITION_VARIABLE_INIT
234 #define CONDITION_VARIABLE_LOCKMODE_SHARED RTL_CONDITION_VARIABLE_LOCKMODE_SHARED
235 #define SRWLOCK_INIT RTL_SRWLOCK_INIT
237 /*Condition Variables http://msdn.microsoft.com/en-us/library/ms682052%28VS.85%29.aspx*/
238 typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE;
239 typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
241 WINBASEAPI VOID WINAPI InitializeConditionVariable(PCONDITION_VARIABLE ConditionVariable);
242 WINBASEAPI WINBOOL WINAPI SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable, PCRITICAL_SECTION CriticalSection, DWORD dwMilliseconds);
243 WINBASEAPI WINBOOL WINAPI SleepConditionVariableSRW(PCONDITION_VARIABLE ConditionVariable, PSRWLOCK SRWLock, DWORD dwMilliseconds, ULONG Flags);
244 WINBASEAPI VOID WINAPI WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable);
245 WINBASEAPI VOID WINAPI WakeConditionVariable(PCONDITION_VARIABLE ConditionVariable);
247 /*Slim Reader/Writer (SRW) Locks http://msdn.microsoft.com/en-us/library/aa904937%28VS.85%29.aspx*/
248 WINBASEAPI VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK SRWLock);
249 WINBASEAPI VOID WINAPI AcquireSRWLockShared(PSRWLOCK SRWLock);
250 WINBASEAPI VOID WINAPI InitializeSRWLock(PSRWLOCK SRWLock);
251 WINBASEAPI VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK SRWLock);
252 WINBASEAPI VOID WINAPI ReleaseSRWLockShared(PSRWLOCK SRWLock);
254 WINBASEAPI BOOLEAN TryAcquireSRWLockExclusive(PSRWLOCK SRWLock);
255 WINBASEAPI BOOLEAN TryAcquireSRWLockShared(PSRWLOCK SRWLock);
257 /*One-Time Initialization http://msdn.microsoft.com/en-us/library/aa363808(VS.85).aspx*/
258 #define INIT_ONCE_ASYNC 0x00000002UL
259 #define INIT_ONCE_INIT_FAILED 0x00000004UL
261 typedef PRTL_RUN_ONCE PINIT_ONCE;
262 typedef PRTL_RUN_ONCE LPINIT_ONCE;
263 typedef WINBOOL CALLBACK (*PINIT_ONCE_FN) (PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context);
265 WINBASEAPI WINBOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, LPVOID *lpContext);
266 WINBASEAPI WINBOOL WINAPI InitOnceComplete(LPINIT_ONCE lpInitOnce, DWORD dwFlags, LPVOID lpContext);
267 WINBASEAPI WINBOOL WINAPI InitOnceExecuteOnce(PINIT_ONCE InitOnce, PINIT_ONCE_FN InitFn, PVOID Parameter, LPVOID *Context);
269 /* https://msdn.microsoft.com/en-us/library/windows/desktop/ms683477(v=vs.85).aspx */
270 WINBASEAPI BOOL WINAPI InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags);
272 #define CRITICAL_SECTION_NO_DEBUG_INFO 0x01000000
274 #endif /* defined __MINGW32__ && !defined __MINGW64_VERSION_MAJOR && (_WIN32_WINNT >= 0x0600) */
276 typedef CRITICAL_SECTION mono_mutex_t;
277 typedef CONDITION_VARIABLE mono_cond_t;
280 mono_os_mutex_init (mono_mutex_t *mutex)
284 res = InitializeCriticalSectionEx (mutex, 0, CRITICAL_SECTION_NO_DEBUG_INFO);
285 if (G_UNLIKELY (res == 0))
286 g_error ("%s: InitializeCriticalSectionEx failed with error %d", __func__, GetLastError ());
290 mono_os_mutex_init_recursive (mono_mutex_t *mutex)
294 res = InitializeCriticalSectionEx (mutex, 0, CRITICAL_SECTION_NO_DEBUG_INFO);
295 if (G_UNLIKELY (res == 0))
296 g_error ("%s: InitializeCriticalSectionEx failed with error %d", __func__, GetLastError ());
300 mono_os_mutex_destroy (mono_mutex_t *mutex)
302 DeleteCriticalSection (mutex);
307 mono_os_mutex_lock (mono_mutex_t *mutex)
309 EnterCriticalSection (mutex);
313 mono_os_mutex_trylock (mono_mutex_t *mutex)
315 return TryEnterCriticalSection (mutex) == 0 ? -1 : 0;
319 mono_os_mutex_unlock (mono_mutex_t *mutex)
321 LeaveCriticalSection (mutex);
325 mono_os_cond_init (mono_cond_t *cond)
327 InitializeConditionVariable (cond);
331 mono_os_cond_destroy (mono_cond_t *cond)
333 /* Beauty of win32 API: do not destroy it */
338 mono_os_cond_wait (mono_cond_t *cond, mono_mutex_t *mutex)
342 res = SleepConditionVariableCS (cond, mutex, INFINITE);
343 if (G_UNLIKELY (res == 0))
344 g_error ("%s: SleepConditionVariableCS failed with error %d", __func__, GetLastError ());
348 mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ms)
352 res = SleepConditionVariableCS (cond, mutex, timeout_ms);
353 if (G_UNLIKELY (res == 0 && GetLastError () != ERROR_TIMEOUT))
354 g_error ("%s: SleepConditionVariableCS failed with error %d", __func__, GetLastError ());
356 return res == 0 ? -1 : 0;
360 mono_os_cond_signal (mono_cond_t *cond)
362 WakeConditionVariable (cond);
366 mono_os_cond_broadcast (mono_cond_t *cond)
368 WakeAllConditionVariable (cond);
375 #endif /* __MONO_OS_MUTEX_H__ */