[runtime] Add documentation to mono-os-{mutex,cond,sem} + Move to .c file
[mono.git] / mono / utils / mono-os-mutex.c
1
2 #include <config.h>
3 #include <glib.h>
4
5 #include <stdlib.h>
6 #include <string.h>
7 #include <time.h>
8
9 #if !defined(HOST_WIN32)
10 #include <pthread.h>
11 #include <errno.h>
12 #else
13 #include <winsock2.h>
14 #include <windows.h>
15 #endif
16
17 #ifdef HAVE_SYS_TIME_H
18 #include <sys/time.h>
19 #endif
20
21 #include "mono-os-mutex.h"
22
23 #if !defined(HOST_WIN32)
24
25 void
26 mono_os_mutex_init (mono_mutex_t *mutex)
27 {
28         gint res;
29
30         res = pthread_mutex_init (mutex, NULL);
31         if (G_UNLIKELY (res != 0))
32                 g_error ("%s: pthread_mutex_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
33 }
34
35 void
36 mono_os_mutex_init_recursive (mono_mutex_t *mutex)
37 {
38         gint res;
39         pthread_mutexattr_t attr;
40
41         res = pthread_mutexattr_init (&attr);
42         if (G_UNLIKELY (res != 0))
43                 g_error ("%s: pthread_mutexattr_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
44
45         res = pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
46         if (G_UNLIKELY (res != 0))
47                 g_error ("%s: pthread_mutexattr_settype failed with \"%s\" (%d)", __func__, g_strerror (res), res);
48
49         res = pthread_mutex_init (mutex, &attr);
50         if (G_UNLIKELY (res != 0))
51                 g_error ("%s: pthread_mutex_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
52
53         res = pthread_mutexattr_destroy (&attr);
54         if (G_UNLIKELY (res != 0))
55                 g_error ("%s: pthread_mutexattr_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
56 }
57
58 gint
59 mono_os_mutex_destroy (mono_mutex_t *mutex)
60 {
61         gint res;
62
63         res = pthread_mutex_destroy (mutex);
64         if (G_UNLIKELY (res != 0 && res != EBUSY))
65                 g_error ("%s: pthread_mutex_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
66
67         return res != 0 ? -1 : 0;
68 }
69
70 void
71 mono_os_mutex_lock (mono_mutex_t *mutex)
72 {
73         gint res;
74
75         res = pthread_mutex_lock (mutex);
76         if (G_UNLIKELY (res != 0))
77                 g_error ("%s: pthread_mutex_lock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
78 }
79
80 gint
81 mono_os_mutex_trylock (mono_mutex_t *mutex)
82 {
83         gint res;
84
85         res = pthread_mutex_trylock (mutex);
86         if (G_UNLIKELY (res != 0 && res != EBUSY))
87                 g_error ("%s: pthread_mutex_trylock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
88
89         return res != 0 ? -1 : 0;
90 }
91
92 void
93 mono_os_mutex_unlock (mono_mutex_t *mutex)
94 {
95         gint res;
96
97         res = pthread_mutex_unlock (mutex);
98         if (G_UNLIKELY (res != 0))
99                 g_error ("%s: pthread_mutex_unlock failed with \"%s\" (%d)", __func__, g_strerror (res), res);
100 }
101
102 void
103 mono_os_cond_init (mono_cond_t *cond)
104 {
105         gint res;
106
107         res = pthread_cond_init (cond, NULL);
108         if (G_UNLIKELY (res != 0))
109                 g_error ("%s: pthread_cond_init failed with \"%s\" (%d)", __func__, g_strerror (res), res);
110 }
111
112 gint
113 mono_os_cond_destroy (mono_cond_t *cond)
114 {
115         gint res;
116
117         res = pthread_cond_destroy (cond);
118         if (G_UNLIKELY (res != 0 && res != EBUSY))
119                 g_error ("%s: pthread_cond_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
120
121         return res != 0 ? -1 : 0;
122 }
123
124 void
125 mono_os_cond_wait (mono_cond_t *cond, mono_mutex_t *mutex)
126 {
127         gint res;
128
129         res = pthread_cond_wait (cond, mutex);
130         if (G_UNLIKELY (res != 0))
131                 g_error ("%s: pthread_cond_wait failed with \"%s\" (%d)", __func__, g_strerror (res), res);
132 }
133
134 gint
135 mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ms)
136 {
137         struct timeval tv;
138         struct timespec ts;
139         gint64 usecs;
140         gint res;
141
142         if (timeout_ms == MONO_INFINITE_WAIT) {
143                 mono_os_cond_wait (cond, mutex);
144                 return 0;
145         }
146
147         /* ms = 10^-3, us = 10^-6, ns = 10^-9 */
148
149         res = gettimeofday (&tv, NULL);
150         if (G_UNLIKELY (res != 0))
151                 g_error ("%s: pthread_cond_timedwait failed with \"%s\" (%d)", __func__, g_strerror (errno), errno);
152
153         tv.tv_sec += timeout_ms / 1000;
154         usecs = tv.tv_usec + ((timeout_ms % 1000) * 1000);
155         if (usecs >= 1000000) {
156                 usecs -= 1000000;
157                 tv.tv_sec ++;
158         }
159         ts.tv_sec = tv.tv_sec;
160         ts.tv_nsec = usecs * 1000;
161
162         res = pthread_cond_timedwait (cond, mutex, &ts);
163         if (G_UNLIKELY (res != 0 && res != ETIMEDOUT))
164                 g_error ("%s: pthread_cond_timedwait failed with \"%s\" (%d)", __func__, g_strerror (res), res);
165
166         return res != 0 ? -1 : 0;
167 }
168
169 void
170 mono_os_cond_signal (mono_cond_t *cond)
171 {
172         gint res;
173
174         res = pthread_cond_signal (cond);
175         if (G_UNLIKELY (res != 0))
176                 g_error ("%s: pthread_cond_signal failed with \"%s\" (%d)", __func__, g_strerror (res), res);
177 }
178
179 void
180 mono_os_cond_broadcast (mono_cond_t *cond)
181 {
182         gint res;
183
184         res = pthread_cond_broadcast (cond);
185         if (G_UNLIKELY (res != 0))
186                 g_error ("%s: pthread_cond_broadcast failed with \"%s\" (%d)", __func__, g_strerror (res), res);
187 }
188
189 #else
190
191 /* Vanilla MinGW is missing some defs, load them from MinGW-w64. */
192 #if defined __MINGW32__ && !defined __MINGW64_VERSION_MAJOR && (_WIN32_WINNT >= 0x0600)
193
194 /* Fixme: Opaque structs */
195 typedef PVOID RTL_CONDITION_VARIABLE;
196
197 #define RTL_SRWLOCK_INIT 0
198 #define RTL_CONDITION_VARIABLE_INIT 0
199 #define RTL_CONDITION_VARIABLE_LOCKMODE_SHARED 1
200
201 /*Condition Variables http://msdn.microsoft.com/en-us/library/ms682052%28VS.85%29.aspx*/
202 typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE;
203
204 WINBASEAPI VOID WINAPI InitializeConditionVariable(PCONDITION_VARIABLE ConditionVariable);
205 WINBASEAPI WINBOOL WINAPI SleepConditionVariableCS(PCONDITION_VARIABLE ConditionVariable, PCRITICAL_SECTION CriticalSection, DWORD dwMilliseconds);
206 WINBASEAPI VOID WINAPI WakeAllConditionVariable(PCONDITION_VARIABLE ConditionVariable);
207 WINBASEAPI VOID WINAPI WakeConditionVariable(PCONDITION_VARIABLE ConditionVariable);
208
209 /* https://msdn.microsoft.com/en-us/library/windows/desktop/ms683477(v=vs.85).aspx */
210 WINBASEAPI BOOL WINAPI InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags);
211
212 #define CRITICAL_SECTION_NO_DEBUG_INFO 0x01000000
213
214 #endif /* defined __MINGW32__ && !defined __MINGW64_VERSION_MAJOR && (_WIN32_WINNT >= 0x0600) */
215
216 void
217 mono_os_mutex_init (mono_mutex_t *mutex)
218 {
219         BOOL res;
220
221         res = InitializeCriticalSectionEx (mutex, 0, CRITICAL_SECTION_NO_DEBUG_INFO);
222         if (G_UNLIKELY (res == 0))
223                 g_error ("%s: InitializeCriticalSectionEx failed with error %d", __func__, GetLastError ());
224 }
225
226 void
227 mono_os_mutex_init_recursive (mono_mutex_t *mutex)
228 {
229         BOOL res;
230
231         res = InitializeCriticalSectionEx (mutex, 0, CRITICAL_SECTION_NO_DEBUG_INFO);
232         if (G_UNLIKELY (res == 0))
233                 g_error ("%s: InitializeCriticalSectionEx failed with error %d", __func__, GetLastError ());
234 }
235
236 gint
237 mono_os_mutex_destroy (mono_mutex_t *mutex)
238 {
239         DeleteCriticalSection (mutex);
240         return 0;
241 }
242
243 void
244 mono_os_mutex_lock (mono_mutex_t *mutex)
245 {
246         EnterCriticalSection (mutex);
247 }
248
249 gint
250 mono_os_mutex_trylock (mono_mutex_t *mutex)
251 {
252         return TryEnterCriticalSection (mutex) == 0 ? -1 : 0;
253 }
254
255 void
256 mono_os_mutex_unlock (mono_mutex_t *mutex)
257 {
258         LeaveCriticalSection (mutex);
259 }
260
261 void
262 mono_os_cond_init (mono_cond_t *cond)
263 {
264         InitializeConditionVariable (cond);
265 }
266
267 gint
268 mono_os_cond_destroy (mono_cond_t *cond)
269 {
270         /* Beauty of win32 API: do not destroy it */
271         return 0;
272 }
273
274 void
275 mono_os_cond_wait (mono_cond_t *cond, mono_mutex_t *mutex)
276 {
277         BOOL res;
278
279         res = SleepConditionVariableCS (cond, mutex, INFINITE);
280         if (G_UNLIKELY (res == 0))
281                 g_error ("%s: SleepConditionVariableCS failed with error %d", __func__, GetLastError ());
282 }
283
284 gint
285 mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ms)
286 {
287         BOOL res;
288
289         res = SleepConditionVariableCS (cond, mutex, timeout_ms);
290         if (G_UNLIKELY (res == 0 && GetLastError () != ERROR_TIMEOUT))
291                 g_error ("%s: SleepConditionVariableCS failed with error %d", __func__, GetLastError ());
292
293         return res == 0 ? -1 : 0;
294 }
295
296 void
297 mono_os_cond_signal (mono_cond_t *cond)
298 {
299         WakeConditionVariable (cond);
300 }
301
302 void
303 mono_os_cond_broadcast (mono_cond_t *cond)
304 {
305         WakeAllConditionVariable (cond);
306 }
307
308 #endif