Add macros to sgen meant to replace DEBUG
[mono-project.git] / mono / io-layer / mono-mutex.c
blobf5152c2f29d5159cb294208ef16ed114f3da6608
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * mono-mutex.h: Portability wrappers around POSIX Mutexes
5 * Authors: Jeffrey Stedfast <fejj@ximian.com>
7 * Copyright 2002 Ximian, Inc. (www.ximian.com)
8 */
11 #ifdef HAVE_CONFIG_H
12 #include <config.h>
13 #endif
15 #include <stdlib.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <assert.h>
19 #include <sys/time.h>
21 #include "mono-mutex.h"
24 #ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
25 /* Android does not implement pthread_mutex_timedlock(), but does provide an
26 * unusual declaration: http://code.google.com/p/android/issues/detail?id=7807
28 #ifdef PLATFORM_ANDROID
29 #define CONST_NEEDED
30 #else
31 #define CONST_NEEDED const
32 #endif
34 int pthread_mutex_timedlock (pthread_mutex_t *mutex,
35 CONST_NEEDED struct timespec *timeout);
36 int
37 pthread_mutex_timedlock (pthread_mutex_t *mutex, CONST_NEEDED struct timespec *timeout)
39 struct timeval timenow;
40 struct timespec sleepytime;
41 int retcode;
43 /* This is just to avoid a completely busy wait */
44 sleepytime.tv_sec = 0;
45 sleepytime.tv_nsec = 10000000; /* 10ms */
47 while ((retcode = pthread_mutex_trylock (mutex)) == EBUSY) {
48 gettimeofday (&timenow, NULL);
50 if (timenow.tv_sec >= timeout->tv_sec &&
51 (timenow.tv_usec * 1000) >= timeout->tv_nsec) {
52 return ETIMEDOUT;
55 nanosleep (&sleepytime, NULL);
58 return retcode;
60 #endif /* HAVE_PTHREAD_MUTEX_TIMEDLOCK */
63 int
64 mono_once (mono_once_t *once, void (*once_init) (void))
66 int thr_ret;
68 if (!once->complete) {
69 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
70 (void *)&once->mutex);
71 thr_ret = pthread_mutex_lock (&once->mutex);
72 g_assert (thr_ret == 0);
74 if (!once->complete) {
75 once_init ();
76 once->complete = TRUE;
78 thr_ret = pthread_mutex_unlock (&once->mutex);
79 g_assert (thr_ret == 0);
81 pthread_cleanup_pop (0);
84 return 0;
88 #ifdef USE_MONO_MUTEX
90 int
91 mono_mutexattr_init (mono_mutexattr_t *attr)
93 memset (attr, 0, sizeof (mono_mutexattr_t));
94 return 0;
97 int
98 mono_mutexattr_settype (mono_mutexattr_t *attr, int type)
100 attr->type = type;
101 return 0;
105 mono_mutexattr_gettype (mono_mutexattr_t *attr, int *type)
107 *type = attr->type;
108 return 0;
112 mono_mutexattr_setpshared (mono_mutexattr_t *attr, int pshared)
114 attr->shared = pshared;
115 return 0;
119 mono_mutexattr_getpshared (mono_mutexattr_t *attr, int *pshared)
121 *pshared = attr->shared;
122 return 0;
126 mono_mutexattr_setprotocol (mono_mutexattr_t *attr, int protocol)
128 attr->protocol = protocol;
129 return 0;
133 mono_mutexattr_getprotocol (mono_mutexattr_t *attr, int *protocol)
135 *protocol = attr->protocol;
136 return 0;
140 mono_mutexattr_setprioceiling (mono_mutexattr_t *attr, int prioceiling)
142 attr->priority = prioceiling;
143 return 0;
147 mono_mutexattr_getprioceiling (mono_mutexattr_t *attr, int *prioceiling)
149 *prioceiling = attr->priority;
150 return 0;
154 mono_mutexattr_destroy (mono_mutexattr_t *attr)
156 return 0;
161 mono_mutex_init (mono_mutex_t *mutex, const mono_mutexattr_t *attr)
163 int ret;
164 int thr_ret;
166 mutex->waiters = 0;
167 mutex->depth = 0;
168 mutex->owner = MONO_THREAD_NONE;
170 if (!attr || attr->type == MONO_MUTEX_NORMAL) {
171 mutex->type = MONO_MUTEX_NORMAL;
172 ret = pthread_mutex_init (&mutex->mutex, NULL);
173 } else {
174 mutex->type = MONO_MUTEX_RECURSIVE;
175 ret = pthread_mutex_init (&mutex->mutex, NULL);
176 thr_ret = pthread_cond_init (&mutex->cond, NULL);
177 g_assert (thr_ret == 0);
180 return(ret);
184 mono_mutex_lock (mono_mutex_t *mutex)
186 pthread_t id;
188 switch (mutex->type) {
189 case MONO_MUTEX_NORMAL:
190 return pthread_mutex_lock (&mutex->mutex);
191 case MONO_MUTEX_RECURSIVE:
192 id = pthread_self ();
193 if (pthread_mutex_lock (&mutex->mutex) != 0)
194 return EINVAL;
196 while (1) {
197 if (pthread_equal (mutex->owner, MONO_THREAD_NONE)) {
198 mutex->owner = id;
199 mutex->depth = 1;
200 break;
201 } else if (pthread_equal (mutex->owner, id)) {
202 mutex->depth++;
203 break;
204 } else {
205 mutex->waiters++;
206 if (pthread_cond_wait (&mutex->cond, &mutex->mutex) != 0)
207 return EINVAL;
208 mutex->waiters--;
212 return pthread_mutex_unlock (&mutex->mutex);
215 return EINVAL;
219 mono_mutex_trylock (mono_mutex_t *mutex)
221 pthread_t id;
223 switch (mutex->type) {
224 case MONO_MUTEX_NORMAL:
225 return pthread_mutex_trylock (&mutex->mutex);
226 case MONO_MUTEX_RECURSIVE:
227 id = pthread_self ();
229 if (pthread_mutex_lock (&mutex->mutex) != 0)
230 return EINVAL;
232 if (!pthread_equal (mutex->owner, MONO_THREAD_NONE) &&
233 !pthread_equal (mutex->owner, id)) {
234 pthread_mutex_unlock (&mutex->mutex);
235 return EBUSY;
238 while (1) {
239 if (pthread_equal (mutex->owner, MONO_THREAD_NONE)) {
240 mutex->owner = id;
241 mutex->depth = 1;
242 break;
243 } else {
244 mutex->depth++;
245 break;
249 return pthread_mutex_unlock (&mutex->mutex);
252 return EINVAL;
256 mono_mutex_timedlock (mono_mutex_t *mutex, const struct timespec *timeout)
258 pthread_t id;
260 switch (mutex->type) {
261 case MONO_MUTEX_NORMAL:
262 return pthread_mutex_timedlock (&mutex->mutex, timeout);
263 case MONO_MUTEX_RECURSIVE:
264 id = pthread_self ();
266 if (pthread_mutex_timedlock (&mutex->mutex, timeout) != 0)
267 return ETIMEDOUT;
269 while (1) {
270 if (pthread_equal (mutex->owner, MONO_THREAD_NONE)) {
271 mutex->owner = id;
272 mutex->depth = 1;
273 break;
274 } else if (pthread_equal (mutex->owner, id)) {
275 mutex->depth++;
276 break;
277 } else {
278 mutex->waiters++;
279 if (pthread_cond_timedwait (&mutex->cond, &mutex->mutex, timeout) != 0)
280 return ETIMEDOUT;
281 mutex->waiters--;
285 return pthread_mutex_unlock (&mutex->mutex);
288 return EINVAL;
292 mono_mutex_unlock (mono_mutex_t *mutex)
294 int thr_ret;
296 switch (mutex->type) {
297 case MONO_MUTEX_NORMAL:
298 return pthread_mutex_unlock (&mutex->mutex);
299 case MONO_MUTEX_RECURSIVE:
300 if (pthread_mutex_lock (&mutex->mutex) != 0)
301 return EINVAL;
303 if (pthread_equal (mutex->owner, pthread_self())) {
304 /* Not owned by this thread */
305 pthread_mutex_unlock (&mutex->mutex);
306 return EPERM;
309 mutex->depth--;
310 if (mutex->depth == 0) {
311 mutex->owner = MONO_THREAD_NONE;
312 if (mutex->waiters > 0) {
313 thr_ret = pthread_cond_signal (&mutex->cond);
314 g_assert (thr_ret == 0);
318 return pthread_mutex_unlock (&mutex->mutex);
321 return EINVAL;
325 mono_mutex_destroy (mono_mutex_t *mutex)
327 int ret = 0;
328 int thr_ret;
330 switch (mutex->type) {
331 case MONO_MUTEX_NORMAL:
332 ret = pthread_mutex_destroy (&mutex->mutex);
333 break;
334 case MONO_MUTEX_RECURSIVE:
335 if ((ret = pthread_mutex_destroy (&mutex->mutex)) == 0) {
336 thr_ret = pthread_cond_destroy (&mutex->cond);
337 g_assert (thr_ret == 0);
341 return ret;
346 mono_cond_wait (pthread_cond_t *cond, mono_mutex_t *mutex)
348 return pthread_cond_wait (cond, &mutex->mutex);
352 mono_cond_timedwait (pthread_cond_t *cond, mono_mutex_t *mutex, const struct timespec *timeout)
354 return pthread_cond_timedwait (cond, &mutex->mutex, timeout);
357 #endif /* USE_MONO_MUTEX */