2010-02-13 Jb Evain <jbevain@novell.com>
[mono-project.git] / mono / io-layer / mono-mutex.c
blob154035a6e5fa64c5f4e049cdb800606d3ae45b5b
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 int pthread_mutex_timedlock (pthread_mutex_t *mutex,
26 const struct timespec *timeout);
28 int
29 pthread_mutex_timedlock (pthread_mutex_t *mutex, const struct timespec *timeout)
31 struct timeval timenow;
32 struct timespec sleepytime;
33 int retcode;
35 /* This is just to avoid a completely busy wait */
36 sleepytime.tv_sec = 0;
37 sleepytime.tv_nsec = 10000000; /* 10ms */
39 while ((retcode = pthread_mutex_trylock (mutex)) == EBUSY) {
40 gettimeofday (&timenow, NULL);
42 if (timenow.tv_sec >= timeout->tv_sec &&
43 (timenow.tv_usec * 1000) >= timeout->tv_nsec) {
44 return ETIMEDOUT;
47 nanosleep (&sleepytime, NULL);
50 return retcode;
52 #endif /* HAVE_PTHREAD_MUTEX_TIMEDLOCK */
55 int
56 mono_once (mono_once_t *once, void (*once_init) (void))
58 int thr_ret;
60 if (!once->complete) {
61 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
62 (void *)&once->mutex);
63 thr_ret = pthread_mutex_lock (&once->mutex);
64 g_assert (thr_ret == 0);
66 if (!once->complete) {
67 once_init ();
68 once->complete = TRUE;
70 thr_ret = pthread_mutex_unlock (&once->mutex);
71 g_assert (thr_ret == 0);
73 pthread_cleanup_pop (0);
76 return 0;
80 #ifdef USE_MONO_MUTEX
82 int
83 mono_mutexattr_init (mono_mutexattr_t *attr)
85 memset (attr, 0, sizeof (mono_mutexattr_t));
86 return 0;
89 int
90 mono_mutexattr_settype (mono_mutexattr_t *attr, int type)
92 attr->type = type;
93 return 0;
96 int
97 mono_mutexattr_gettype (mono_mutexattr_t *attr, int *type)
99 *type = attr->type;
100 return 0;
104 mono_mutexattr_setpshared (mono_mutexattr_t *attr, int pshared)
106 attr->shared = pshared;
107 return 0;
111 mono_mutexattr_getpshared (mono_mutexattr_t *attr, int *pshared)
113 *pshared = attr->shared;
114 return 0;
118 mono_mutexattr_setprotocol (mono_mutexattr_t *attr, int protocol)
120 attr->protocol = protocol;
121 return 0;
125 mono_mutexattr_getprotocol (mono_mutexattr_t *attr, int *protocol)
127 *protocol = attr->protocol;
128 return 0;
132 mono_mutexattr_setprioceiling (mono_mutexattr_t *attr, int prioceiling)
134 attr->priority = prioceiling;
135 return 0;
139 mono_mutexattr_getprioceiling (mono_mutexattr_t *attr, int *prioceiling)
141 *prioceiling = attr->priority;
142 return 0;
146 mono_mutexattr_destroy (mono_mutexattr_t *attr)
148 return 0;
153 mono_mutex_init (mono_mutex_t *mutex, const mono_mutexattr_t *attr)
155 int ret;
156 int thr_ret;
158 mutex->waiters = 0;
159 mutex->depth = 0;
160 mutex->owner = MONO_THREAD_NONE;
162 if (!attr || attr->type == MONO_MUTEX_NORMAL) {
163 mutex->type = MONO_MUTEX_NORMAL;
164 ret = pthread_mutex_init (&mutex->mutex, NULL);
165 } else {
166 mutex->type = MONO_MUTEX_RECURSIVE;
167 ret = pthread_mutex_init (&mutex->mutex, NULL);
168 thr_ret = pthread_cond_init (&mutex->cond, NULL);
169 g_assert (thr_ret == 0);
172 return(ret);
176 mono_mutex_lock (mono_mutex_t *mutex)
178 pthread_t id;
180 switch (mutex->type) {
181 case MONO_MUTEX_NORMAL:
182 return pthread_mutex_lock (&mutex->mutex);
183 case MONO_MUTEX_RECURSIVE:
184 id = pthread_self ();
185 if (pthread_mutex_lock (&mutex->mutex) != 0)
186 return EINVAL;
188 while (1) {
189 if (pthread_equal (mutex->owner, MONO_THREAD_NONE)) {
190 mutex->owner = id;
191 mutex->depth = 1;
192 break;
193 } else if (pthread_equal (mutex->owner, id)) {
194 mutex->depth++;
195 break;
196 } else {
197 mutex->waiters++;
198 if (pthread_cond_wait (&mutex->cond, &mutex->mutex) != 0)
199 return EINVAL;
200 mutex->waiters--;
204 return pthread_mutex_unlock (&mutex->mutex);
207 return EINVAL;
211 mono_mutex_trylock (mono_mutex_t *mutex)
213 pthread_t id;
215 switch (mutex->type) {
216 case MONO_MUTEX_NORMAL:
217 return pthread_mutex_trylock (&mutex->mutex);
218 case MONO_MUTEX_RECURSIVE:
219 id = pthread_self ();
221 if (pthread_mutex_lock (&mutex->mutex) != 0)
222 return EINVAL;
224 if (!pthread_equal (mutex->owner, MONO_THREAD_NONE) &&
225 !pthread_equal (mutex->owner, id)) {
226 pthread_mutex_unlock (&mutex->mutex);
227 return EBUSY;
230 while (1) {
231 if (pthread_equal (mutex->owner, MONO_THREAD_NONE)) {
232 mutex->owner = id;
233 mutex->depth = 1;
234 break;
235 } else {
236 mutex->depth++;
237 break;
241 return pthread_mutex_unlock (&mutex->mutex);
244 return EINVAL;
248 mono_mutex_timedlock (mono_mutex_t *mutex, const struct timespec *timeout)
250 pthread_t id;
252 switch (mutex->type) {
253 case MONO_MUTEX_NORMAL:
254 return pthread_mutex_timedlock (&mutex->mutex, timeout);
255 case MONO_MUTEX_RECURSIVE:
256 id = pthread_self ();
258 if (pthread_mutex_timedlock (&mutex->mutex, timeout) != 0)
259 return ETIMEDOUT;
261 while (1) {
262 if (pthread_equal (mutex->owner, MONO_THREAD_NONE)) {
263 mutex->owner = id;
264 mutex->depth = 1;
265 break;
266 } else if (pthread_equal (mutex->owner, id)) {
267 mutex->depth++;
268 break;
269 } else {
270 mutex->waiters++;
271 if (pthread_cond_timedwait (&mutex->cond, &mutex->mutex, timeout) != 0)
272 return ETIMEDOUT;
273 mutex->waiters--;
277 return pthread_mutex_unlock (&mutex->mutex);
280 return EINVAL;
284 mono_mutex_unlock (mono_mutex_t *mutex)
286 int thr_ret;
288 switch (mutex->type) {
289 case MONO_MUTEX_NORMAL:
290 return pthread_mutex_unlock (&mutex->mutex);
291 case MONO_MUTEX_RECURSIVE:
292 if (pthread_mutex_lock (&mutex->mutex) != 0)
293 return EINVAL;
295 if (pthread_equal (mutex->owner, pthread_self())) {
296 /* Not owned by this thread */
297 pthread_mutex_unlock (&mutex->mutex);
298 return EPERM;
301 mutex->depth--;
302 if (mutex->depth == 0) {
303 mutex->owner = MONO_THREAD_NONE;
304 if (mutex->waiters > 0) {
305 thr_ret = pthread_cond_signal (&mutex->cond);
306 g_assert (thr_ret == 0);
310 return pthread_mutex_unlock (&mutex->mutex);
313 return EINVAL;
317 mono_mutex_destroy (mono_mutex_t *mutex)
319 int ret = 0;
320 int thr_ret;
322 switch (mutex->type) {
323 case MONO_MUTEX_NORMAL:
324 ret = pthread_mutex_destroy (&mutex->mutex);
325 break;
326 case MONO_MUTEX_RECURSIVE:
327 if ((ret = pthread_mutex_destroy (&mutex->mutex)) == 0) {
328 thr_ret = pthread_cond_destroy (&mutex->cond);
329 g_assert (thr_ret == 0);
333 return ret;
338 mono_cond_wait (pthread_cond_t *cond, mono_mutex_t *mutex)
340 return pthread_cond_wait (cond, &mutex->mutex);
344 mono_cond_timedwait (pthread_cond_t *cond, mono_mutex_t *mutex, const struct timespec *timeout)
346 return pthread_cond_timedwait (cond, &mutex->mutex, timeout);
349 #endif /* USE_MONO_MUTEX */