Implementation of GetLoopbackInterfaceIndex on Windows
[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 int
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 && res != EBUSY))
86                 g_error ("%s: pthread_mutex_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
87
88         return res != 0 ? -1 : 0;
89 }
90
91 static inline void
92 mono_os_mutex_lock (mono_mutex_t *mutex)
93 {
94         int res;
95
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);
99 }
100
101 static inline int
102 mono_os_mutex_trylock (mono_mutex_t *mutex)
103 {
104         int res;
105
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);
109
110         return res != 0 ? -1 : 0;
111 }
112
113 static inline void
114 mono_os_mutex_unlock (mono_mutex_t *mutex)
115 {
116         int res;
117
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);
121 }
122
123 static inline void
124 mono_os_cond_init (mono_cond_t *cond)
125 {
126         int res;
127
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);
131 }
132
133 static inline int
134 mono_os_cond_destroy (mono_cond_t *cond)
135 {
136         int res;
137
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);
141
142         return res != 0 ? -1 : 0;
143 }
144
145 static inline void
146 mono_os_cond_wait (mono_cond_t *cond, mono_mutex_t *mutex)
147 {
148         int res;
149
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);
153 }
154
155 static inline int
156 mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ms)
157 {
158         struct timeval tv;
159         struct timespec ts;
160         gint64 usecs;
161         int res;
162
163         if (timeout_ms == MONO_INFINITE_WAIT) {
164                 mono_os_cond_wait (cond, mutex);
165                 return 0;
166         }
167
168         /* ms = 10^-3, us = 10^-6, ns = 10^-9 */
169
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);
173
174         tv.tv_sec += timeout_ms / 1000;
175         usecs = tv.tv_usec + ((timeout_ms % 1000) * 1000);
176         if (usecs >= 1000000) {
177                 usecs -= 1000000;
178                 tv.tv_sec ++;
179         }
180         ts.tv_sec = tv.tv_sec;
181         ts.tv_nsec = usecs * 1000;
182
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);
186
187         return res != 0 ? -1 : 0;
188 }
189
190 static inline void
191 mono_os_cond_signal (mono_cond_t *cond)
192 {
193         int res;
194
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);
198 }
199
200 static inline void
201 mono_os_cond_broadcast (mono_cond_t *cond)
202 {
203         int res;
204
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);
208 }
209
210 #else
211
212 /* Vanilla MinGW is missing some defs, load them from MinGW-w64. */
213 #if defined __MINGW32__ && !defined __MINGW64_VERSION_MAJOR && (_WIN32_WINNT >= 0x0600)
214
215 /* Fixme: Opaque structs */
216 typedef PVOID RTL_CONDITION_VARIABLE;
217 typedef PVOID RTL_SRWLOCK;
218
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
232
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
236
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;
240
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);
246
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);
253
254 WINBASEAPI BOOLEAN TryAcquireSRWLockExclusive(PSRWLOCK SRWLock);
255 WINBASEAPI BOOLEAN TryAcquireSRWLockShared(PSRWLOCK SRWLock);
256
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
260
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);
264
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);
268
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);
271
272 #define CRITICAL_SECTION_NO_DEBUG_INFO 0x01000000
273
274 #endif /* defined __MINGW32__ && !defined __MINGW64_VERSION_MAJOR && (_WIN32_WINNT >= 0x0600) */
275
276 typedef CRITICAL_SECTION mono_mutex_t;
277 typedef CONDITION_VARIABLE mono_cond_t;
278
279 static inline void
280 mono_os_mutex_init (mono_mutex_t *mutex)
281 {
282         BOOL res;
283
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 ());
287 }
288
289 static inline void
290 mono_os_mutex_init_recursive (mono_mutex_t *mutex)
291 {
292         BOOL res;
293
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 ());
297 }
298
299 static inline int
300 mono_os_mutex_destroy (mono_mutex_t *mutex)
301 {
302         DeleteCriticalSection (mutex);
303         return 0;
304 }
305
306 static inline void
307 mono_os_mutex_lock (mono_mutex_t *mutex)
308 {
309         EnterCriticalSection (mutex);
310 }
311
312 static inline int
313 mono_os_mutex_trylock (mono_mutex_t *mutex)
314 {
315         return TryEnterCriticalSection (mutex) == 0 ? -1 : 0;
316 }
317
318 static inline void
319 mono_os_mutex_unlock (mono_mutex_t *mutex)
320 {
321         LeaveCriticalSection (mutex);
322 }
323
324 static inline void
325 mono_os_cond_init (mono_cond_t *cond)
326 {
327         InitializeConditionVariable (cond);
328 }
329
330 static inline int
331 mono_os_cond_destroy (mono_cond_t *cond)
332 {
333         /* Beauty of win32 API: do not destroy it */
334         return 0;
335 }
336
337 static inline void
338 mono_os_cond_wait (mono_cond_t *cond, mono_mutex_t *mutex)
339 {
340         BOOL res;
341
342         res = SleepConditionVariableCS (cond, mutex, INFINITE);
343         if (G_UNLIKELY (res == 0))
344                 g_error ("%s: SleepConditionVariableCS failed with error %d", __func__, GetLastError ());
345 }
346
347 static inline int
348 mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ms)
349 {
350         BOOL res;
351
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 ());
355
356         return res == 0 ? -1 : 0;
357 }
358
359 static inline void
360 mono_os_cond_signal (mono_cond_t *cond)
361 {
362         WakeConditionVariable (cond);
363 }
364
365 static inline void
366 mono_os_cond_broadcast (mono_cond_t *cond)
367 {
368         WakeAllConditionVariable (cond);
369 }
370
371 #endif
372
373 G_END_DECLS
374
375 #endif /* __MONO_OS_MUTEX_H__ */