summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorM Joonas Pihlaja <jpihlaja@cc.helsinki.fi>2010-05-06 22:47:36 +0300
committerM Joonas Pihlaja <jpihlaja@cc.helsinki.fi>2010-05-07 03:45:06 +0300
commitef7e4d4e4958de8847381575b84cc0537ec2b661 (patch)
tree9f1c44aab9134cba53a1d58b45dd5dff343ad5ff
parentcc77a93c7333e5df9ae500b39ca234ddb52e64e9 (diff)
Support mutex type attributes.mutexattr
This patch adds support for the pthread_mutex_settype() function. To have correct single-threaded semantics for PTHREAD_MUTEX_ERRORCHECK kind mutexes, the patch also implements the following functions: pthread_mutex_init, pthread_mutex_lock, pthread_mutex_unlock, pthread_mutexattr_gettype, pthread_mutexattr_init, pthread_mutexattr_destroy If any one of these functions is not implemented by the host system, then all of them are provided by pthread-stubs. This is to avoid mismatches between pthread-stubs and the host.
-rw-r--r--list.m434
-rw-r--r--stubs.c.m4171
2 files changed, 190 insertions, 15 deletions
diff --git a/list.m4 b/list.m4
index 01f5e6f..9a97952 100644
--- a/list.m4
+++ b/list.m4
@@ -1,15 +1,19 @@
-alias(zero, pthread_t, pthread_self)
-alias(zero, int, pthread_mutex_init)
-alias(zero, int, pthread_mutex_destroy)
-alias(zero, int, pthread_mutex_lock)
-alias(zero, int, pthread_mutex_unlock)
-alias(zero, int, pthread_cond_init)
-alias(zero, int, pthread_cond_destroy)
-alias(zero, int, pthread_condattr_init)
-alias(zero, int, pthread_condattr_destroy)
-alias(abort, int, pthread_cond_wait)
-alias(abort, int, pthread_cond_timedwait)
-alias(zero, int, pthread_cond_signal)
-alias(zero, int, pthread_cond_broadcast)
-alias(equal, int, pthread_equal)
-alias(exit, void, pthread_exit)
+alias(zero, pthread_t, pthread_self)
+alias(mutex_init, int, pthread_mutex_init)
+alias(zero, int, pthread_mutex_destroy)
+alias(mutex_lock, int, pthread_mutex_lock)
+alias(mutex_unlock, int, pthread_mutex_unlock)
+alias(zero, int, pthread_cond_init)
+alias(zero, int, pthread_cond_destroy)
+alias(zero, int, pthread_condattr_init)
+alias(zero, int, pthread_condattr_destroy)
+alias(abort, int, pthread_cond_wait)
+alias(abort, int, pthread_cond_timedwait)
+alias(zero, int, pthread_cond_signal)
+alias(zero, int, pthread_cond_broadcast)
+alias(equal, int, pthread_equal)
+alias(exit, void, pthread_exit)
+alias(zero, int, pthread_mutexattr_destroy)
+alias(mutexattr_init, int, pthread_mutexattr_init)
+alias(mutexattr_settype, int, pthread_mutexattr_settype)
+alias(mutexattr_gettype, int, pthread_mutexattr_gettype)
diff --git a/stubs.c.m4 b/stubs.c.m4
index d2cb428..87fff4f 100644
--- a/stubs.c.m4
+++ b/stubs.c.m4
@@ -12,6 +12,19 @@ m4_define([alias], [dnl
#endif
])
+# dependency_group(<group_name>, [<functions>...])
+# Declare that if any function in the function list needs
+# to be stubbed using our implementation, then all of them do.
+# If our implementations are used, then additionally #define
+# NEED_<GROUP_NAME>.
+m4_define([dependency_group],[dnl
+#if m4_foreach([x], [$2], [!defined(HAVE_[]upcase(x)) || ])0
+# define NEED_[]upcase($1) 1
+m4_foreach([x], [$2], [dnl
+# undef HAVE_[]upcase(x)
+])dnl
+#endif])
+
m4_divert(0)dnl
/* Copyright (C) 2006 Diego Pettenò
* Copyright (C) 2010 M Joonas Pihlaja
@@ -44,8 +57,28 @@ m4_divert(0)dnl
#include <pthread.h>
#include <stdlib.h>
+#include <errno.h>
#include "config.h"
+/* Gah.. linux pthreads doesn't give us the posix mutex types by
+ * default. Map them manually. */
+#if defined(__linux__)
+# define PTHREAD_MUTEX_NORMAL PTHREAD_MUTEX_TIMED_NP
+# define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
+# define PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_ERRORCHECK_NP
+# define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
+#endif
+
+dependency_group(MUTEXATTR_GROUP, [
+ pthread_mutex_init,
+ pthread_mutex_destroy,
+ pthread_mutex_lock,
+ pthread_mutex_unlock,
+ pthread_mutexattr_init,
+ pthread_mutexattr_destroy,
+ pthread_mutexattr_settype,
+ pthread_mutexattr_gettype])
+
m4_include([list.m4])
#ifdef NEED_ZERO_STUB
@@ -75,3 +108,141 @@ static void __pthread_exit_stub(void *ret)
exit(EXIT_SUCCESS);
}
#endif
+
+#if NEED_MUTEXATTR_GROUP
+typedef struct {
+ int mutex_type;
+} __pthread_mutexattr_stub_t;
+
+typedef struct {
+ unsigned locked_count;
+ __pthread_mutexattr_stub_t attr;
+} __pthread_mutex_stub_t;
+#endif
+
+#ifdef NEED_MUTEXATTR_INIT_STUB
+static int __pthread_mutexattr_init_stub(__pthread_mutexattr_stub_t *attr)
+{
+ if (!attr) return EINVAL;
+ attr->mutex_type = PTHREAD_MUTEX_DEFAULT;
+ return 0;
+}
+#endif
+
+#ifdef NEED_MUTEXATTR_SETTYPE_STUB
+static int __pthread_mutexattr_settype_stub(__pthread_mutexattr_stub_t *attr,
+ int type)
+{
+ if (!attr) return EINVAL;
+ if (type == PTHREAD_MUTEX_NORMAL ||
+ type == PTHREAD_MUTEX_ERRORCHECK ||
+ type == PTHREAD_MUTEX_RECURSIVE ||
+ type == PTHREAD_MUTEX_DEFAULT)
+ {
+ attr->mutex_type = type;
+ return 0;
+ }
+ return EINVAL;
+}
+#endif
+
+#ifdef NEED_MUTEXATTR_GETTYPE_STUB
+static int __pthread_mutexattr_gettype_stub(__pthread_mutexattr_stub_t *attr,
+ int *type)
+{
+ if (!attr || !type) return EINVAL;
+ *type = attr->mutex_type;
+ return 0;
+}
+#endif
+
+#ifdef NEED_MUTEX_INIT_STUB
+static int __pthread_mutex_init_stub(__pthread_mutex_stub_t *mutex,
+ __pthread_mutexattr_stub_t *attr)
+{
+ if (!mutex) return EINVAL;
+ mutex->locked_count = 0;
+ if (attr) {
+ mutex->attr = *attr;
+ } else {
+ __pthread_mutexattr_init_stub(&mutex->attr);
+ }
+ return 0;
+}
+#endif
+
+#ifdef NEED_MUTEX_LOCK_STUB
+static int __pthread_mutex_lock_stub(__pthread_mutex_stub_t *mutex)
+{
+ int type;
+ if (!mutex) return EINVAL;
+
+ if (mutex->locked_count == 0) {
+ mutex->locked_count = 1;
+ return 0;
+ }
+
+ type = mutex->attr.mutex_type;
+
+ if (type == PTHREAD_MUTEX_RECURSIVE) {
+ if (mutex->locked_count+1 == 0)
+ /* "The mutex could not be acquired because the maximum
+ * number of recursive locks for mutex has been
+ * exceeded." */
+ return EAGAIN;
+ ++mutex->locked_count;
+ return 0;
+ }
+
+ if (type == PTHREAD_MUTEX_NORMAL) {
+ /* "If the mutex type is PTHREAD_MUTEX_NORMAL, deadlock
+ * detection shall not be provided. Attempting to relock the
+ * mutex causes deadlock." Uh... okay. :| */
+ while (1) {}
+ return EDEADLK;
+ }
+
+ if (type == PTHREAD_MUTEX_DEFAULT ||
+ type == PTHREAD_MUTEX_ERRORCHECK)
+ {
+ /* "If the mutex type is PTHREAD_MUTEX_DEFAULT, attempting to
+ * recursively lock the mutex results in undefined
+ * behavior." */
+ /* "If a thread attempts to relock a
+ * [PTHREAD_MUTEX_ERRORCHECK] mutex that it has already
+ * locked, an error shall be returned." */
+ return EDEADLK;
+ }
+
+ /* "The value specified by mutex does not refer to an
+ * initialized mutex object." */
+ return EINVAL;
+}
+#endif
+
+#ifdef NEED_MUTEX_UNLOCK_STUB
+static int __pthread_mutex_unlock_stub(__pthread_mutex_stub_t *mutex)
+{
+ if (!mutex) return EINVAL;
+
+ if (mutex->locked_count == 0)
+ /* "The current thread does not own the mutex." */
+ return EPERM;
+
+ if (mutex->locked_count == 1) {
+ mutex->locked_count = 0;
+ return 0;
+ }
+
+ if (mutex->attr.mutex_type == PTHREAD_MUTEX_RECURSIVE) {
+ --mutex->locked_count;
+ return 0;
+ }
+
+ /* "The value specified by mutex does not refer to an initialized
+ * mutex object." */
+ /* or "undefined behaviour." */
+ /* or "an error shall be returned." */
+ return EINVAL;
+}
+#endif