Change clock source to CLOCK_MONOTONIC in 'pthread_cond_timedwait'
[mono.git] / mono / utils / mono-os-mutex.h
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * mono-os-mutex.h: Portability wrappers around POSIX Mutexes
4  *
5  * Authors: Jeffrey Stedfast <fejj@ximian.com>
6  *
7  * Copyright 2002 Ximian, Inc. (www.ximian.com)
8  *
9  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
10  */
11
12 #ifndef __MONO_OS_MUTEX_H__
13 #define __MONO_OS_MUTEX_H__
14
15 #include <config.h>
16 #include <glib.h>
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <time.h>
21
22 #if !defined(HOST_WIN32)
23 #include <pthread.h>
24 #include <errno.h>
25 #else
26 #include <winsock2.h>
27 #include <windows.h>
28 #endif
29
30 #ifdef HAVE_SYS_TIME_H
31 #include <sys/time.h>
32 #endif
33
34 G_BEGIN_DECLS
35
36 #ifndef MONO_INFINITE_WAIT
37 #define MONO_INFINITE_WAIT ((guint32) 0xFFFFFFFF)
38 #endif
39
40
41 #if !defined(HOST_WIN32)
42
43 typedef pthread_mutex_t mono_mutex_t;
44 typedef pthread_cond_t mono_cond_t;
45
46 static inline void
47 mono_os_mutex_init (mono_mutex_t *mutex)
48 {
49         int res;
50
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);
54 }
55
56 static inline void
57 mono_os_mutex_init_recursive (mono_mutex_t *mutex)
58 {
59         int res;
60         pthread_mutexattr_t attr;
61
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);
65
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);
69
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);
73
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);
77 }
78
79 static inline void
80 mono_os_mutex_destroy (mono_mutex_t *mutex)
81 {
82         int res;
83
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);
87 }
88
89 static inline void
90 mono_os_mutex_lock (mono_mutex_t *mutex)
91 {
92         int res;
93
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);
97 }
98
99 static inline int
100 mono_os_mutex_trylock (mono_mutex_t *mutex)
101 {
102         int res;
103
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);
107
108         return res != 0 ? -1 : 0;
109 }
110
111 static inline void
112 mono_os_mutex_unlock (mono_mutex_t *mutex)
113 {
114         int res;
115
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);
119 }
120
121 static inline void
122 mono_os_cond_init (mono_cond_t *cond)
123 {
124         int res;
125
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);
130 #else
131         /* POSIX standard does not compel to have CLOCK_MONOTONIC */
132         pthread_condattr_t attr;
133
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);
137
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);
141
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);
146
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);
150 #endif
151 }
152
153 static inline void
154 mono_os_cond_destroy (mono_cond_t *cond)
155 {
156         int res;
157
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);
161 }
162
163 static inline void
164 mono_os_cond_wait (mono_cond_t *cond, mono_mutex_t *mutex)
165 {
166         int res;
167
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);
171 }
172
173 static inline int
174 mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ms)
175 {
176 #if !defined(CLOCK_MONOTONIC) || defined(PLATFORM_MACOSX)
177         struct timeval tv;
178 #endif
179         struct timespec ts;
180         int res;
181
182         if (timeout_ms == MONO_INFINITE_WAIT) {
183                 mono_os_cond_wait (cond, mutex);
184                 return 0;
185         }
186
187         /* ms = 10^-3, us = 10^-6, ns = 10^-9 */
188
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);
194
195         ts.tv_sec = tv.tv_sec;
196         ts.tv_nsec = tv.tv_usec * 1000;
197 #else
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);
202 #endif
203
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;
208                 ts.tv_sec ++;
209         }
210
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);
214
215         return res != 0 ? -1 : 0;
216 }
217
218 static inline void
219 mono_os_cond_signal (mono_cond_t *cond)
220 {
221         int res;
222
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);
226 }
227
228 static inline void
229 mono_os_cond_broadcast (mono_cond_t *cond)
230 {
231         int res;
232
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);
236 }
237
238 #else
239
240 /* Vanilla MinGW is missing some defs, load them from MinGW-w64. */
241 #if defined __MINGW32__ && !defined __MINGW64_VERSION_MAJOR && (_WIN32_WINNT >= 0x0600)
242
243 /* Fixme: Opaque structs */
244 typedef PVOID RTL_CONDITION_VARIABLE;
245 typedef PVOID RTL_SRWLOCK;
246
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
260
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
264
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;
268
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);
274
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);
281
282 WINBASEAPI BOOLEAN TryAcquireSRWLockExclusive(PSRWLOCK SRWLock);
283 WINBASEAPI BOOLEAN TryAcquireSRWLockShared(PSRWLOCK SRWLock);
284
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
288
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);
292
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);
296
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);
299
300 #define CRITICAL_SECTION_NO_DEBUG_INFO 0x01000000
301
302 #endif /* defined __MINGW32__ && !defined __MINGW64_VERSION_MAJOR && (_WIN32_WINNT >= 0x0600) */
303
304 typedef CRITICAL_SECTION mono_mutex_t;
305 typedef CONDITION_VARIABLE mono_cond_t;
306
307 static inline void
308 mono_os_mutex_init (mono_mutex_t *mutex)
309 {
310         BOOL res;
311
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 ());
315 }
316
317 static inline void
318 mono_os_mutex_init_recursive (mono_mutex_t *mutex)
319 {
320         BOOL res;
321
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 ());
325 }
326
327 static inline void
328 mono_os_mutex_destroy (mono_mutex_t *mutex)
329 {
330         DeleteCriticalSection (mutex);
331 }
332
333 static inline void
334 mono_os_mutex_lock (mono_mutex_t *mutex)
335 {
336         EnterCriticalSection (mutex);
337 }
338
339 static inline int
340 mono_os_mutex_trylock (mono_mutex_t *mutex)
341 {
342         return TryEnterCriticalSection (mutex) == 0 ? -1 : 0;
343 }
344
345 static inline void
346 mono_os_mutex_unlock (mono_mutex_t *mutex)
347 {
348         LeaveCriticalSection (mutex);
349 }
350
351 static inline void
352 mono_os_cond_init (mono_cond_t *cond)
353 {
354         InitializeConditionVariable (cond);
355 }
356
357 static inline void
358 mono_os_cond_destroy (mono_cond_t *cond)
359 {
360         /* Beauty of win32 API: do not destroy it */
361 }
362
363 static inline void
364 mono_os_cond_wait (mono_cond_t *cond, mono_mutex_t *mutex)
365 {
366         BOOL res;
367
368         res = SleepConditionVariableCS (cond, mutex, INFINITE);
369         if (G_UNLIKELY (res == 0))
370                 g_error ("%s: SleepConditionVariableCS failed with error %d", __func__, GetLastError ());
371 }
372
373 static inline int
374 mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ms)
375 {
376         BOOL res;
377
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 ());
381
382         return res == 0 ? -1 : 0;
383 }
384
385 static inline void
386 mono_os_cond_signal (mono_cond_t *cond)
387 {
388         WakeConditionVariable (cond);
389 }
390
391 static inline void
392 mono_os_cond_broadcast (mono_cond_t *cond)
393 {
394         WakeAllConditionVariable (cond);
395 }
396
397 #endif
398
399 G_END_DECLS
400
401 #endif /* __MONO_OS_MUTEX_H__ */