1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /**
3  * \file
4  * Portability wrappers around POSIX Mutexes
5  *
6  * Authors: Jeffrey Stedfast <fejj@ximian.com>
7  *
8  * Copyright 2002 Ximian, Inc. (www.ximian.com)
9  *
10  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11  */
12 
13 #ifndef __MONO_OS_MUTEX_H__
14 #define __MONO_OS_MUTEX_H__
15 
16 #include <config.h>
17 #include <glib.h>
18 
19 #include <stdlib.h>
20 #include <string.h>
21 #include <time.h>
22 
23 #if !defined(HOST_WIN32)
24 #include <pthread.h>
25 #include <errno.h>
26 #else
27 #include <winsock2.h>
28 #include <windows.h>
29 #endif
30 
31 #ifdef HAVE_SYS_TIME_H
32 #include <sys/time.h>
33 #endif
34 
35 G_BEGIN_DECLS
36 
37 #ifndef MONO_INFINITE_WAIT
38 #define MONO_INFINITE_WAIT ((guint32) 0xFFFFFFFF)
39 #endif
40 
41 
42 #if !defined(HOST_WIN32)
43 
44 #if !defined(CLOCK_MONOTONIC) || defined(HOST_DARWIN) || defined(HOST_ANDROID) || defined(HOST_WASM)
45 #define BROKEN_CLOCK_SOURCE
46 #endif
47 
48 typedef pthread_mutex_t mono_mutex_t;
49 typedef pthread_cond_t mono_cond_t;
50 
51 static inline void
mono_os_mutex_init(mono_mutex_t * mutex)52 mono_os_mutex_init (mono_mutex_t *mutex)
53 {
54 	int res;
55 
56 	res = pthread_mutex_init (mutex, NULL);
57 	if (G_UNLIKELY (res != 0))
58 		g_error ("%s: pthread_mutex_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
59 }
60 
61 static inline void
mono_os_mutex_init_recursive(mono_mutex_t * mutex)62 mono_os_mutex_init_recursive (mono_mutex_t *mutex)
63 {
64 	int res;
65 	pthread_mutexattr_t attr;
66 
67 	res = pthread_mutexattr_init (&attr);
68 	if (G_UNLIKELY (res != 0))
69 		g_error ("%s: pthread_mutexattr_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
70 
71 	res = pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
72 	if (G_UNLIKELY (res != 0))
73 		g_error ("%s: pthread_mutexattr_settype failed with \"%s\" (%d)", __func__, g_strerror (res), res);
74 
75 	res = pthread_mutex_init (mutex, &attr);
76 	if (G_UNLIKELY (res != 0))
77 		g_error ("%s: pthread_mutex_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
78 
79 	res = pthread_mutexattr_destroy (&attr);
80 	if (G_UNLIKELY (res != 0))
81 		g_error ("%s: pthread_mutexattr_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
82 }
83 
84 static inline void
mono_os_mutex_destroy(mono_mutex_t * mutex)85 mono_os_mutex_destroy (mono_mutex_t *mutex)
86 {
87 	int res;
88 
89 	res = pthread_mutex_destroy (mutex);
90 	if (G_UNLIKELY (res != 0))
91 		g_error ("%s: pthread_mutex_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
92 }
93 
94 static inline void
mono_os_mutex_lock(mono_mutex_t * mutex)95 mono_os_mutex_lock (mono_mutex_t *mutex)
96 {
97 	int res;
98 
99 	res = pthread_mutex_lock (mutex);
100 	if (G_UNLIKELY (res != 0))
101 		g_error ("%s: pthread_mutex_lock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
102 }
103 
104 static inline int
mono_os_mutex_trylock(mono_mutex_t * mutex)105 mono_os_mutex_trylock (mono_mutex_t *mutex)
106 {
107 	int res;
108 
109 	res = pthread_mutex_trylock (mutex);
110 	if (G_UNLIKELY (res != 0 && res != EBUSY))
111 		g_error ("%s: pthread_mutex_trylock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
112 
113 	return res != 0 ? -1 : 0;
114 }
115 
116 static inline void
mono_os_mutex_unlock(mono_mutex_t * mutex)117 mono_os_mutex_unlock (mono_mutex_t *mutex)
118 {
119 	int res;
120 
121 	res = pthread_mutex_unlock (mutex);
122 	if (G_UNLIKELY (res != 0))
123 		g_error ("%s: pthread_mutex_unlock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
124 }
125 
126 static inline void
mono_os_cond_init(mono_cond_t * cond)127 mono_os_cond_init (mono_cond_t *cond)
128 {
129 	int res;
130 
131 #ifdef BROKEN_CLOCK_SOURCE
132 	res = pthread_cond_init (cond, NULL);
133 	if (G_UNLIKELY (res != 0))
134 		g_error ("%s: pthread_cond_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
135 #else
136 	/* POSIX standard does not compel to have CLOCK_MONOTONIC */
137 	pthread_condattr_t attr;
138 
139 	res = pthread_condattr_init (&attr);
140 	if (G_UNLIKELY (res != 0))
141 		g_error ("%s: pthread_condattr_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
142 
143 	res = pthread_condattr_setclock (&attr, CLOCK_MONOTONIC);
144 	if (G_UNLIKELY (res != 0))
145 		g_error ("%s: pthread_condattr_setclock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
146 
147 	/* Attach an attribute having CLOCK_MONOTONIC to condition */
148 	res = pthread_cond_init (cond, &attr);
149 	if (G_UNLIKELY (res != 0))
150 		g_error ("%s: pthread_cond_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
151 
152 	res = pthread_condattr_destroy (&attr);
153 	if (G_UNLIKELY (res != 0))
154 		g_error ("%s: pthread_condattr_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
155 #endif
156 }
157 
158 static inline void
mono_os_cond_destroy(mono_cond_t * cond)159 mono_os_cond_destroy (mono_cond_t *cond)
160 {
161 	int res;
162 
163 	res = pthread_cond_destroy (cond);
164 	if (G_UNLIKELY (res != 0))
165 		g_error ("%s: pthread_cond_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
166 }
167 
168 static inline void
mono_os_cond_wait(mono_cond_t * cond,mono_mutex_t * mutex)169 mono_os_cond_wait (mono_cond_t *cond, mono_mutex_t *mutex)
170 {
171 	int res;
172 
173 	res = pthread_cond_wait (cond, mutex);
174 	if (G_UNLIKELY (res != 0))
175 		g_error ("%s: pthread_cond_wait failed with \"%s\" (%d)", __func__, g_strerror (res), res);
176 }
177 
178 int
179 mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ms);
180 
181 static inline void
mono_os_cond_signal(mono_cond_t * cond)182 mono_os_cond_signal (mono_cond_t *cond)
183 {
184 	int res;
185 
186 	res = pthread_cond_signal (cond);
187 	if (G_UNLIKELY (res != 0))
188 		g_error ("%s: pthread_cond_signal failed with \"%s\" (%d)", __func__, g_strerror (res), res);
189 }
190 
191 static inline void
mono_os_cond_broadcast(mono_cond_t * cond)192 mono_os_cond_broadcast (mono_cond_t *cond)
193 {
194 	int res;
195 
196 	res = pthread_cond_broadcast (cond);
197 	if (G_UNLIKELY (res != 0))
198 		g_error ("%s: pthread_cond_broadcast failed with \"%s\" (%d)", __func__, g_strerror (res), res);
199 }
200 
201 #else
202 
203 /* Vanilla MinGW is missing some defs, load them from MinGW-w64. */
204 #if defined __MINGW32__ && !defined __MINGW64_VERSION_MAJOR && (_WIN32_WINNT >= 0x0600)
205 
206 /* Fixme: Opaque structs */
207 typedef PVOID RTL_CONDITION_VARIABLE;
208 typedef PVOID RTL_SRWLOCK;
209 
210 #ifndef _RTL_RUN_ONCE_DEF
211 #define _RTL_RUN_ONCE_DEF 1
212 typedef PVOID RTL_RUN_ONCE, *PRTL_RUN_ONCE;
213 typedef DWORD (WINAPI *PRTL_RUN_ONCE_INIT_FN)(PRTL_RUN_ONCE, PVOID, PVOID *);
214 #define RTL_RUN_ONCE_INIT 0
215 #define RTL_RUN_ONCE_CHECK_ONLY 1UL
216 #define RTL_RUN_ONCE_ASYNC 2UL
217 #define RTL_RUN_ONCE_INIT_FAILED 4UL
218 #define RTL_RUN_ONCE_CTX_RESERVED_BITS 2
219 #endif /* _RTL_RUN_ONCE_DEF */
220 #define RTL_SRWLOCK_INIT 0
221 #define RTL_CONDITION_VARIABLE_INIT 0
222 #define RTL_CONDITION_VARIABLE_LOCKMODE_SHARED 1
223 
224 #define CONDITION_VARIABLE_INIT RTL_CONDITION_VARIABLE_INIT
225 #define CONDITION_VARIABLE_LOCKMODE_SHARED RTL_CONDITION_VARIABLE_LOCKMODE_SHARED
226 #define SRWLOCK_INIT RTL_SRWLOCK_INIT
227 
228 /*Condition Variables http://msdn.microsoft.com/en-us/library/ms682052%28VS.85%29.aspx*/
229 typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE;
230 typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
231 
232 WINBASEAPI VOID WINAPI InitializeConditionVariable(PCONDITION_VARIABLE ConditionVariable);
233 WINBASEAPI WINBOOL WINAPI SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable, PCRITICAL_SECTION CriticalSection, DWORD dwMilliseconds);
234 WINBASEAPI WINBOOL WINAPI SleepConditionVariableSRW(PCONDITION_VARIABLE ConditionVariable, PSRWLOCK SRWLock, DWORD dwMilliseconds, ULONG Flags);
235 WINBASEAPI VOID WINAPI WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable);
236 WINBASEAPI VOID WINAPI WakeConditionVariable(PCONDITION_VARIABLE ConditionVariable);
237 
238 /*Slim Reader/Writer (SRW) Locks http://msdn.microsoft.com/en-us/library/aa904937%28VS.85%29.aspx*/
239 WINBASEAPI VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK SRWLock);
240 WINBASEAPI VOID WINAPI AcquireSRWLockShared(PSRWLOCK SRWLock);
241 WINBASEAPI VOID WINAPI InitializeSRWLock(PSRWLOCK SRWLock);
242 WINBASEAPI VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK SRWLock);
243 WINBASEAPI VOID WINAPI ReleaseSRWLockShared(PSRWLOCK SRWLock);
244 
245 WINBASEAPI BOOLEAN TryAcquireSRWLockExclusive(PSRWLOCK SRWLock);
246 WINBASEAPI BOOLEAN TryAcquireSRWLockShared(PSRWLOCK SRWLock);
247 
248 /*One-Time Initialization http://msdn.microsoft.com/en-us/library/aa363808(VS.85).aspx*/
249 #define INIT_ONCE_ASYNC 0x00000002UL
250 #define INIT_ONCE_INIT_FAILED 0x00000004UL
251 
252 typedef PRTL_RUN_ONCE PINIT_ONCE;
253 typedef PRTL_RUN_ONCE LPINIT_ONCE;
254 typedef WINBOOL CALLBACK (*PINIT_ONCE_FN) (PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context);
255 
256 WINBASEAPI WINBOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, LPVOID *lpContext);
257 WINBASEAPI WINBOOL WINAPI InitOnceComplete(LPINIT_ONCE lpInitOnce, DWORD dwFlags, LPVOID lpContext);
258 WINBASEAPI WINBOOL WINAPI InitOnceExecuteOnce(PINIT_ONCE InitOnce, PINIT_ONCE_FN InitFn, PVOID Parameter, LPVOID *Context);
259 
260 /* https://msdn.microsoft.com/en-us/library/windows/desktop/ms683477(v=vs.85).aspx */
261 WINBASEAPI BOOL WINAPI InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags);
262 
263 #define CRITICAL_SECTION_NO_DEBUG_INFO 0x01000000
264 
265 #endif /* defined __MINGW32__ && !defined __MINGW64_VERSION_MAJOR && (_WIN32_WINNT >= 0x0600) */
266 
267 typedef CRITICAL_SECTION mono_mutex_t;
268 typedef CONDITION_VARIABLE mono_cond_t;
269 
270 static inline void
271 mono_os_mutex_init (mono_mutex_t *mutex)
272 {
273 	BOOL res;
274 
275 	res = InitializeCriticalSectionEx (mutex, 0, CRITICAL_SECTION_NO_DEBUG_INFO);
276 	if (G_UNLIKELY (res == 0))
277 		g_error ("%s: InitializeCriticalSectionEx failed with error %d", __func__, GetLastError ());
278 }
279 
280 static inline void
281 mono_os_mutex_init_recursive (mono_mutex_t *mutex)
282 {
283 	BOOL res;
284 
285 	res = InitializeCriticalSectionEx (mutex, 0, CRITICAL_SECTION_NO_DEBUG_INFO);
286 	if (G_UNLIKELY (res == 0))
287 		g_error ("%s: InitializeCriticalSectionEx failed with error %d", __func__, GetLastError ());
288 }
289 
290 static inline void
291 mono_os_mutex_destroy (mono_mutex_t *mutex)
292 {
293 	DeleteCriticalSection (mutex);
294 }
295 
296 static inline void
297 mono_os_mutex_lock (mono_mutex_t *mutex)
298 {
299 	EnterCriticalSection (mutex);
300 }
301 
302 static inline int
303 mono_os_mutex_trylock (mono_mutex_t *mutex)
304 {
305 	return TryEnterCriticalSection (mutex) == 0 ? -1 : 0;
306 }
307 
308 static inline void
309 mono_os_mutex_unlock (mono_mutex_t *mutex)
310 {
311 	LeaveCriticalSection (mutex);
312 }
313 
314 static inline void
315 mono_os_cond_init (mono_cond_t *cond)
316 {
317 	InitializeConditionVariable (cond);
318 }
319 
320 static inline void
321 mono_os_cond_destroy (mono_cond_t *cond)
322 {
323 	/* Beauty of win32 API: do not destroy it */
324 }
325 
326 static inline void
327 mono_os_cond_wait (mono_cond_t *cond, mono_mutex_t *mutex)
328 {
329 	BOOL res;
330 
331 	res = SleepConditionVariableCS (cond, mutex, INFINITE);
332 	if (G_UNLIKELY (res == 0))
333 		g_error ("%s: SleepConditionVariableCS failed with error %d", __func__, GetLastError ());
334 }
335 
336 static inline int
337 mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ms)
338 {
339 	BOOL res;
340 
341 	res = SleepConditionVariableCS (cond, mutex, timeout_ms);
342 	if (G_UNLIKELY (res == 0 && GetLastError () != ERROR_TIMEOUT))
343 		g_error ("%s: SleepConditionVariableCS failed with error %d", __func__, GetLastError ());
344 
345 	return res == 0 ? -1 : 0;
346 }
347 
348 static inline void
349 mono_os_cond_signal (mono_cond_t *cond)
350 {
351 	WakeConditionVariable (cond);
352 }
353 
354 static inline void
355 mono_os_cond_broadcast (mono_cond_t *cond)
356 {
357 	WakeAllConditionVariable (cond);
358 }
359 
360 #endif
361 
362 G_END_DECLS
363 
364 #endif /* __MONO_OS_MUTEX_H__ */
365