Implement vararg support for s390. Minor fix to atomic operation for s390.
[mono.git] / mono / io-layer / mono-mutex.c
blob104c36b46fccfcb2990172a26973adb034123222
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Authors: Jeffrey Stedfast <fejj@ximian.com>
5 * Copyright 2002 Ximain, Inc. (www.ximian.com)
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <assert.h>
32 #include <sys/time.h>
34 #include "mono-mutex.h"
37 #ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
38 int pthread_mutex_timedlock (pthread_mutex_t *mutex,
39 const struct timespec *timeout);
41 int
42 pthread_mutex_timedlock (pthread_mutex_t *mutex, const struct timespec *timeout)
44 struct timeval timenow;
45 struct timespec sleepytime;
46 int retcode;
48 /* This is just to avoid a completely busy wait */
49 sleepytime.tv_sec = 0;
50 sleepytime.tv_nsec = 10000000; /* 10ms */
52 while ((retcode = pthread_mutex_trylock (mutex)) == EBUSY) {
53 gettimeofday (&timenow, NULL);
55 if (timenow.tv_sec >= timeout->tv_sec &&
56 (timenow.tv_usec * 1000) >= timeout->tv_nsec) {
57 return ETIMEDOUT;
60 nanosleep (&sleepytime, NULL);
63 return retcode;
65 #endif /* HAVE_PTHREAD_MUTEX_TIMEDLOCK */
68 int
69 mono_once (mono_once_t *once, void (*once_init) (void))
71 int thr_ret;
73 if (!once->complete) {
74 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
75 (void *)&once->mutex);
76 thr_ret = pthread_mutex_lock (&once->mutex);
77 g_assert (thr_ret == 0);
79 if (!once->complete) {
80 once_init ();
81 once->complete = TRUE;
83 thr_ret = pthread_mutex_unlock (&once->mutex);
84 g_assert (thr_ret == 0);
86 pthread_cleanup_pop (0);
89 return 0;
93 #ifdef USE_MONO_MUTEX
95 int
96 mono_mutexattr_init (mono_mutexattr_t *attr)
98 memset (attr, 0, sizeof (mono_mutexattr_t));
99 return 0;
103 mono_mutexattr_settype (mono_mutexattr_t *attr, int type)
105 attr->type = type;
106 return 0;
110 mono_mutexattr_gettype (mono_mutexattr_t *attr, int *type)
112 *type = attr->type;
113 return 0;
117 mono_mutexattr_setpshared (mono_mutexattr_t *attr, int pshared)
119 attr->shared = pshared;
120 return 0;
124 mono_mutexattr_getpshared (mono_mutexattr_t *attr, int *pshared)
126 *pshared = attr->shared;
127 return 0;
131 mono_mutexattr_setprotocol (mono_mutexattr_t *attr, int protocol)
133 attr->protocol = protocol;
134 return 0;
138 mono_mutexattr_getprotocol (mono_mutexattr_t *attr, int *protocol)
140 *protocol = attr->protocol;
141 return 0;
145 mono_mutexattr_setprioceiling (mono_mutexattr_t *attr, int prioceiling)
147 attr->priority = prioceiling;
148 return 0;
152 mono_mutexattr_getprioceiling (mono_mutexattr_t *attr, int *prioceiling)
154 *prioceiling = attr->priority;
155 return 0;
159 mono_mutexattr_destroy (mono_mutexattr_t *attr)
161 return 0;
166 mono_mutex_init (mono_mutex_t *mutex, const mono_mutexattr_t *attr)
168 int ret;
169 int thr_ret;
171 mutex->waiters = 0;
172 mutex->depth = 0;
173 mutex->owner = MONO_THREAD_NONE;
175 if (!attr || attr->type == MONO_MUTEX_NORMAL) {
176 mutex->type = MONO_MUTEX_NORMAL;
177 ret = pthread_mutex_init (&mutex->mutex, NULL);
178 } else {
179 mutex->type = MONO_MUTEX_RECURSIVE;
180 ret = pthread_mutex_init (&mutex->mutex, NULL);
181 thr_ret = pthread_cond_init (&mutex->cond, NULL);
182 g_assert (thr_ret == 0);
185 return(ret);
189 mono_mutex_lock (mono_mutex_t *mutex)
191 pthread_t id;
193 switch (mutex->type) {
194 case MONO_MUTEX_NORMAL:
195 return pthread_mutex_lock (&mutex->mutex);
196 case MONO_MUTEX_RECURSIVE:
197 id = pthread_self ();
198 if (pthread_mutex_lock (&mutex->mutex) != 0)
199 return EINVAL;
201 while (1) {
202 if (mutex->owner == MONO_THREAD_NONE) {
203 mutex->owner = id;
204 mutex->depth = 1;
205 break;
206 } else if (mutex->owner == id) {
207 mutex->depth++;
208 break;
209 } else {
210 mutex->waiters++;
211 if (pthread_cond_wait (&mutex->cond, &mutex->mutex) != 0)
212 return EINVAL;
213 mutex->waiters--;
217 return pthread_mutex_unlock (&mutex->mutex);
220 return EINVAL;
224 mono_mutex_trylock (mono_mutex_t *mutex)
226 pthread_t id;
228 switch (mutex->type) {
229 case MONO_MUTEX_NORMAL:
230 return pthread_mutex_trylock (&mutex->mutex);
231 case MONO_MUTEX_RECURSIVE:
232 id = pthread_self ();
234 if (pthread_mutex_lock (&mutex->mutex) != 0)
235 return EINVAL;
237 if (mutex->owner != MONO_THREAD_NONE && mutex->owner != id) {
238 pthread_mutex_unlock (&mutex->mutex);
239 return EBUSY;
242 while (1) {
243 if (mutex->owner == MONO_THREAD_NONE) {
244 mutex->owner = id;
245 mutex->depth = 1;
246 break;
247 } else {
248 mutex->depth++;
249 break;
253 return pthread_mutex_unlock (&mutex->mutex);
256 return EINVAL;
260 mono_mutex_timedlock (mono_mutex_t *mutex, const struct timespec *timeout)
262 pthread_t id;
264 switch (mutex->type) {
265 case MONO_MUTEX_NORMAL:
266 return pthread_mutex_timedlock (&mutex->mutex, timeout);
267 case MONO_MUTEX_RECURSIVE:
268 id = pthread_self ();
270 if (pthread_mutex_timedlock (&mutex->mutex, timeout) != 0)
271 return ETIMEDOUT;
273 while (1) {
274 if (mutex->owner == MONO_THREAD_NONE) {
275 mutex->owner = id;
276 mutex->depth = 1;
277 break;
278 } else if (mutex->owner == id) {
279 mutex->depth++;
280 break;
281 } else {
282 mutex->waiters++;
283 if (pthread_cond_timedwait (&mutex->cond, &mutex->mutex, timeout) != 0)
284 return ETIMEDOUT;
285 mutex->waiters--;
289 return pthread_mutex_unlock (&mutex->mutex);
292 return EINVAL;
296 mono_mutex_unlock (mono_mutex_t *mutex)
298 int thr_ret;
300 switch (mutex->type) {
301 case MONO_MUTEX_NORMAL:
302 return pthread_mutex_unlock (&mutex->mutex);
303 case MONO_MUTEX_RECURSIVE:
304 if (pthread_mutex_lock (&mutex->mutex) != 0)
305 return EINVAL;
307 if (mutex->owner != pthread_self()) {
308 /* Not owned by this thread */
309 pthread_mutex_unlock (&mutex->mutex);
310 return EPERM;
313 mutex->depth--;
314 if (mutex->depth == 0) {
315 mutex->owner = MONO_THREAD_NONE;
316 if (mutex->waiters > 0) {
317 thr_ret = pthread_cond_signal (&mutex->cond);
318 g_assert (thr_ret == 0);
322 return pthread_mutex_unlock (&mutex->mutex);
325 return EINVAL;
329 mono_mutex_destroy (mono_mutex_t *mutex)
331 int ret = 0;
332 int thr_ret;
334 switch (mutex->type) {
335 case MONO_MUTEX_NORMAL:
336 ret = pthread_mutex_destroy (&mutex->mutex);
337 break;
338 case MONO_MUTEX_RECURSIVE:
339 if ((ret = pthread_mutex_destroy (&mutex->mutex)) == 0) {
340 thr_ret = pthread_cond_destroy (&mutex->cond);
341 g_assert (thr_ret == 0);
345 return ret;
350 mono_cond_wait (pthread_cond_t *cond, mono_mutex_t *mutex)
352 return pthread_cond_wait (cond, &mutex->mutex);
356 mono_cond_timedwait (pthread_cond_t *cond, mono_mutex_t *mutex, const struct timespec *timeout)
358 return pthread_cond_timedwait (cond, &mutex->mutex, timeout);
361 #endif /* USE_MONO_MUTEX */