/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
- * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ * mono-mutex.h: Portability wrappers around POSIX Mutexes
*
- * Copyright 2002 Ximain, Inc. (www.ximian.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
*
+ * Copyright 2002 Ximian, Inc. (www.ximian.com)
*/
#include <string.h>
#include <errno.h>
#include <assert.h>
+#include <sys/time.h>
#include "mono-mutex.h"
#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
+/* Android does not implement pthread_mutex_timedlock(), but does provide an
+ * unusual declaration: http://code.google.com/p/android/issues/detail?id=7807
+ */
+#ifdef PLATFORM_ANDROID
+#define CONST_NEEDED
+#else
+#define CONST_NEEDED const
+#endif
+
+int pthread_mutex_timedlock (pthread_mutex_t *mutex,
+ CONST_NEEDED struct timespec *timeout);
int
-pthread_mutex_timedlock (pthread_mutex_t *mutex, const struct timespec *timeout)
+pthread_mutex_timedlock (pthread_mutex_t *mutex, CONST_NEEDED struct timespec *timeout)
{
struct timeval timenow;
struct timespec sleepytime;
/* This is just to avoid a completely busy wait */
sleepytime.tv_sec = 0;
- sleepytime.tv_nsec = 10000; /* 10ms */
+ sleepytime.tv_nsec = 10000000; /* 10ms */
while ((retcode = pthread_mutex_trylock (mutex)) == EBUSY) {
gettimeofday (&timenow, NULL);
#endif /* HAVE_PTHREAD_MUTEX_TIMEDLOCK */
+int
+mono_once (mono_once_t *once, void (*once_init) (void))
+{
+ int thr_ret;
+
+ if (!once->complete) {
+ pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+ (void *)&once->mutex);
+ thr_ret = pthread_mutex_lock (&once->mutex);
+ g_assert (thr_ret == 0);
+
+ if (!once->complete) {
+ once_init ();
+ once->complete = TRUE;
+ }
+ thr_ret = pthread_mutex_unlock (&once->mutex);
+ g_assert (thr_ret == 0);
+
+ pthread_cleanup_pop (0);
+ }
+
+ return 0;
+}
+
#ifdef USE_MONO_MUTEX
int
mono_mutex_init (mono_mutex_t *mutex, const mono_mutexattr_t *attr)
{
+ int ret;
+ int thr_ret;
+
mutex->waiters = 0;
mutex->depth = 0;
mutex->owner = MONO_THREAD_NONE;
if (!attr || attr->type == MONO_MUTEX_NORMAL) {
mutex->type = MONO_MUTEX_NORMAL;
- pthread_mutex_init (&mutex->mutex, NULL);
+ ret = pthread_mutex_init (&mutex->mutex, NULL);
} else {
mutex->type = MONO_MUTEX_RECURSIVE;
- pthread_mutex_init (&mutex->mutex, NULL);
- pthread_cond_init (&mutex->cond, NULL);
+ ret = pthread_mutex_init (&mutex->mutex, NULL);
+ thr_ret = pthread_cond_init (&mutex->cond, NULL);
+ g_assert (thr_ret == 0);
}
- return 0;
+ return(ret);
}
int
return EINVAL;
while (1) {
- if (mutex->owner == MONO_THREAD_NONE) {
+ if (pthread_equal (mutex->owner, MONO_THREAD_NONE)) {
mutex->owner = id;
mutex->depth = 1;
break;
- } else if (mutex->owner == id) {
+ } else if (pthread_equal (mutex->owner, id)) {
mutex->depth++;
break;
} else {
mutex->waiters++;
- if (pthread_cond_wait (&mutex->cond, &mutex->mutex) == -1)
+ if (pthread_cond_wait (&mutex->cond, &mutex->mutex) != 0)
return EINVAL;
mutex->waiters--;
}
if (pthread_mutex_lock (&mutex->mutex) != 0)
return EINVAL;
- if (mutex->owner != MONO_THREAD_NONE && mutex->owner != id) {
+ if (!pthread_equal (mutex->owner, MONO_THREAD_NONE) &&
+ !pthread_equal (mutex->owner, id)) {
pthread_mutex_unlock (&mutex->mutex);
return EBUSY;
}
while (1) {
- if (mutex->owner == MONO_THREAD_NONE) {
+ if (pthread_equal (mutex->owner, MONO_THREAD_NONE)) {
mutex->owner = id;
mutex->depth = 1;
break;
return ETIMEDOUT;
while (1) {
- if (mutex->owner == MONO_THREAD_NONE) {
+ if (pthread_equal (mutex->owner, MONO_THREAD_NONE)) {
mutex->owner = id;
mutex->depth = 1;
break;
- } else if (mutex->owner == id) {
+ } else if (pthread_equal (mutex->owner, id)) {
mutex->depth++;
break;
} else {
int
mono_mutex_unlock (mono_mutex_t *mutex)
{
+ int thr_ret;
+
switch (mutex->type) {
case MONO_MUTEX_NORMAL:
return pthread_mutex_unlock (&mutex->mutex);
if (pthread_mutex_lock (&mutex->mutex) != 0)
return EINVAL;
- assert (mutex->owner == pthread_self ());
+ if (pthread_equal (mutex->owner, pthread_self())) {
+ /* Not owned by this thread */
+ pthread_mutex_unlock (&mutex->mutex);
+ return EPERM;
+ }
mutex->depth--;
if (mutex->depth == 0) {
mutex->owner = MONO_THREAD_NONE;
- if (mutex->waiters > 0)
- pthread_cond_signal (&mutex->cond);
+ if (mutex->waiters > 0) {
+ thr_ret = pthread_cond_signal (&mutex->cond);
+ g_assert (thr_ret == 0);
+ }
}
return pthread_mutex_unlock (&mutex->mutex);
mono_mutex_destroy (mono_mutex_t *mutex)
{
int ret = 0;
+ int thr_ret;
switch (mutex->type) {
case MONO_MUTEX_NORMAL:
break;
case MONO_MUTEX_RECURSIVE:
if ((ret = pthread_mutex_destroy (&mutex->mutex)) == 0) {
- pthread_cond_destroy (&mutex->cond);
+ thr_ret = pthread_cond_destroy (&mutex->cond);
+ g_assert (thr_ret == 0);
}
}