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 res
= pthread_cond_init (cond
, NULL
);
127 if (G_UNLIKELY (res
!= 0))
128 g_error ("%s: pthread_cond_init failed with \"%s\" (%d)", __func__
, g_strerror (res
), res
);
132 mono_os_cond_destroy (mono_cond_t
*cond
)
136 res
= pthread_cond_destroy (cond
);
137 if (G_UNLIKELY (res
!= 0))
138 g_error ("%s: pthread_cond_destroy failed with \"%s\" (%d)", __func__
, g_strerror (res
), res
);
142 mono_os_cond_wait (mono_cond_t
*cond
, mono_mutex_t
*mutex
)
146 res
= pthread_cond_wait (cond
, mutex
);
147 if (G_UNLIKELY (res
!= 0))
148 g_error ("%s: pthread_cond_wait failed with \"%s\" (%d)", __func__
, g_strerror (res
), res
);
152 mono_os_cond_timedwait (mono_cond_t
*cond
, mono_mutex_t
*mutex
, guint32 timeout_ms
)
159 if (timeout_ms
== MONO_INFINITE_WAIT
) {
160 mono_os_cond_wait (cond
, mutex
);
164 /* ms = 10^-3, us = 10^-6, ns = 10^-9 */
166 res
= gettimeofday (&tv
, NULL
);
167 if (G_UNLIKELY (res
!= 0))
168 g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__
, g_strerror (errno
), errno
);
170 tv
.tv_sec
+= timeout_ms
/ 1000;
171 usecs
= tv
.tv_usec
+ ((timeout_ms
% 1000) * 1000);
172 if (usecs
>= 1000000) {
176 ts
.tv_sec
= tv
.tv_sec
;
177 ts
.tv_nsec
= usecs
* 1000;
179 res
= pthread_cond_timedwait (cond
, mutex
, &ts
);
180 if (G_UNLIKELY (res
!= 0 && res
!= ETIMEDOUT
))
181 g_error ("%s: pthread_cond_timedwait failed with \"%s\" (%d)", __func__
, g_strerror (res
), res
);
183 return res
!= 0 ? -1 : 0;
187 mono_os_cond_signal (mono_cond_t
*cond
)
191 res
= pthread_cond_signal (cond
);
192 if (G_UNLIKELY (res
!= 0))
193 g_error ("%s: pthread_cond_signal failed with \"%s\" (%d)", __func__
, g_strerror (res
), res
);
197 mono_os_cond_broadcast (mono_cond_t
*cond
)
201 res
= pthread_cond_broadcast (cond
);
202 if (G_UNLIKELY (res
!= 0))
203 g_error ("%s: pthread_cond_broadcast failed with \"%s\" (%d)", __func__
, g_strerror (res
), res
);
208 /* Vanilla MinGW is missing some defs, load them from MinGW-w64. */
209 #if defined __MINGW32__ && !defined __MINGW64_VERSION_MAJOR && (_WIN32_WINNT >= 0x0600)
211 /* Fixme: Opaque structs */
212 typedef PVOID RTL_CONDITION_VARIABLE
;
213 typedef PVOID RTL_SRWLOCK
;
215 #ifndef _RTL_RUN_ONCE_DEF
216 #define _RTL_RUN_ONCE_DEF 1
217 typedef PVOID RTL_RUN_ONCE
, *PRTL_RUN_ONCE
;
218 typedef DWORD (WINAPI
*PRTL_RUN_ONCE_INIT_FN
)(PRTL_RUN_ONCE
, PVOID
, PVOID
*);
219 #define RTL_RUN_ONCE_INIT 0
220 #define RTL_RUN_ONCE_CHECK_ONLY 1UL
221 #define RTL_RUN_ONCE_ASYNC 2UL
222 #define RTL_RUN_ONCE_INIT_FAILED 4UL
223 #define RTL_RUN_ONCE_CTX_RESERVED_BITS 2
224 #endif /* _RTL_RUN_ONCE_DEF */
225 #define RTL_SRWLOCK_INIT 0
226 #define RTL_CONDITION_VARIABLE_INIT 0
227 #define RTL_CONDITION_VARIABLE_LOCKMODE_SHARED 1
229 #define CONDITION_VARIABLE_INIT RTL_CONDITION_VARIABLE_INIT
230 #define CONDITION_VARIABLE_LOCKMODE_SHARED RTL_CONDITION_VARIABLE_LOCKMODE_SHARED
231 #define SRWLOCK_INIT RTL_SRWLOCK_INIT
233 /*Condition Variables http://msdn.microsoft.com/en-us/library/ms682052%28VS.85%29.aspx*/
234 typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE
, *PCONDITION_VARIABLE
;
235 typedef RTL_SRWLOCK SRWLOCK
, *PSRWLOCK
;
237 WINBASEAPI VOID WINAPI
InitializeConditionVariable(PCONDITION_VARIABLE ConditionVariable
);
238 WINBASEAPI WINBOOL WINAPI
SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable
, PCRITICAL_SECTION CriticalSection
, DWORD dwMilliseconds
);
239 WINBASEAPI WINBOOL WINAPI
SleepConditionVariableSRW(PCONDITION_VARIABLE ConditionVariable
, PSRWLOCK SRWLock
, DWORD dwMilliseconds
, ULONG Flags
);
240 WINBASEAPI VOID WINAPI
WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable
);
241 WINBASEAPI VOID WINAPI
WakeConditionVariable(PCONDITION_VARIABLE ConditionVariable
);
243 /*Slim Reader/Writer (SRW) Locks http://msdn.microsoft.com/en-us/library/aa904937%28VS.85%29.aspx*/
244 WINBASEAPI VOID WINAPI
AcquireSRWLockExclusive(PSRWLOCK SRWLock
);
245 WINBASEAPI VOID WINAPI
AcquireSRWLockShared(PSRWLOCK SRWLock
);
246 WINBASEAPI VOID WINAPI
InitializeSRWLock(PSRWLOCK SRWLock
);
247 WINBASEAPI VOID WINAPI
ReleaseSRWLockExclusive(PSRWLOCK SRWLock
);
248 WINBASEAPI VOID WINAPI
ReleaseSRWLockShared(PSRWLOCK SRWLock
);
250 WINBASEAPI BOOLEAN
TryAcquireSRWLockExclusive(PSRWLOCK SRWLock
);
251 WINBASEAPI BOOLEAN
TryAcquireSRWLockShared(PSRWLOCK SRWLock
);
253 /*One-Time Initialization http://msdn.microsoft.com/en-us/library/aa363808(VS.85).aspx*/
254 #define INIT_ONCE_ASYNC 0x00000002UL
255 #define INIT_ONCE_INIT_FAILED 0x00000004UL
257 typedef PRTL_RUN_ONCE PINIT_ONCE
;
258 typedef PRTL_RUN_ONCE LPINIT_ONCE
;
259 typedef WINBOOL
CALLBACK (*PINIT_ONCE_FN
) (PINIT_ONCE InitOnce
, PVOID Parameter
, PVOID
*Context
);
261 WINBASEAPI WINBOOL WINAPI
InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce
, DWORD dwFlags
, PBOOL fPending
, LPVOID
*lpContext
);
262 WINBASEAPI WINBOOL WINAPI
InitOnceComplete(LPINIT_ONCE lpInitOnce
, DWORD dwFlags
, LPVOID lpContext
);
263 WINBASEAPI WINBOOL WINAPI
InitOnceExecuteOnce(PINIT_ONCE InitOnce
, PINIT_ONCE_FN InitFn
, PVOID Parameter
, LPVOID
*Context
);
265 /* https://msdn.microsoft.com/en-us/library/windows/desktop/ms683477(v=vs.85).aspx */
266 WINBASEAPI BOOL WINAPI
InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection
, DWORD dwSpinCount
, DWORD Flags
);
268 #define CRITICAL_SECTION_NO_DEBUG_INFO 0x01000000
270 #endif /* defined __MINGW32__ && !defined __MINGW64_VERSION_MAJOR && (_WIN32_WINNT >= 0x0600) */
272 typedef CRITICAL_SECTION mono_mutex_t
;
273 typedef CONDITION_VARIABLE mono_cond_t
;
276 mono_os_mutex_init (mono_mutex_t
*mutex
)
280 res
= InitializeCriticalSectionEx (mutex
, 0, CRITICAL_SECTION_NO_DEBUG_INFO
);
281 if (G_UNLIKELY (res
== 0))
282 g_error ("%s: InitializeCriticalSectionEx failed with error %d", __func__
, GetLastError ());
286 mono_os_mutex_init_recursive (mono_mutex_t
*mutex
)
290 res
= InitializeCriticalSectionEx (mutex
, 0, CRITICAL_SECTION_NO_DEBUG_INFO
);
291 if (G_UNLIKELY (res
== 0))
292 g_error ("%s: InitializeCriticalSectionEx failed with error %d", __func__
, GetLastError ());
296 mono_os_mutex_destroy (mono_mutex_t
*mutex
)
298 DeleteCriticalSection (mutex
);
302 mono_os_mutex_lock (mono_mutex_t
*mutex
)
304 EnterCriticalSection (mutex
);
308 mono_os_mutex_trylock (mono_mutex_t
*mutex
)
310 return TryEnterCriticalSection (mutex
) == 0 ? -1 : 0;
314 mono_os_mutex_unlock (mono_mutex_t
*mutex
)
316 LeaveCriticalSection (mutex
);
320 mono_os_cond_init (mono_cond_t
*cond
)
322 InitializeConditionVariable (cond
);
326 mono_os_cond_destroy (mono_cond_t
*cond
)
328 /* Beauty of win32 API: do not destroy it */
332 mono_os_cond_wait (mono_cond_t
*cond
, mono_mutex_t
*mutex
)
336 res
= SleepConditionVariableCS (cond
, mutex
, INFINITE
);
337 if (G_UNLIKELY (res
== 0))
338 g_error ("%s: SleepConditionVariableCS failed with error %d", __func__
, GetLastError ());
342 mono_os_cond_timedwait (mono_cond_t
*cond
, mono_mutex_t
*mutex
, guint32 timeout_ms
)
346 res
= SleepConditionVariableCS (cond
, mutex
, timeout_ms
);
347 if (G_UNLIKELY (res
== 0 && GetLastError () != ERROR_TIMEOUT
))
348 g_error ("%s: SleepConditionVariableCS failed with error %d", __func__
, GetLastError ());
350 return res
== 0 ? -1 : 0;
354 mono_os_cond_signal (mono_cond_t
*cond
)
356 WakeConditionVariable (cond
);
360 mono_os_cond_broadcast (mono_cond_t
*cond
)
362 WakeAllConditionVariable (cond
);
369 #endif /* __MONO_OS_MUTEX_H__ */