about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2011-03-17 20:41:37 -0400
committerRich Felker <dalias@aerifal.cx>2011-03-17 20:41:37 -0400
commit047e434ef5fd5437a74f98f63c40a77a683f7f3f (patch)
tree30102ca55dc34c2b5ec078e3b3ab7891abcccb5f
parent18c7ea8055cf733f168d2c74d7cc8523a360f5f1 (diff)
downloadmusl-047e434ef5fd5437a74f98f63c40a77a683f7f3f.tar.gz
musl-047e434ef5fd5437a74f98f63c40a77a683f7f3f.tar.xz
musl-047e434ef5fd5437a74f98f63c40a77a683f7f3f.zip
implement robust mutexes
some of this code should be cleaned up, e.g. using macros for some of
the bit flags, masks, etc. nonetheless, the code is believed to be
working and correct at this point.
-rw-r--r--include/pthread.h1
-rw-r--r--src/internal/pthread_impl.h5
-rw-r--r--src/thread/pthread_mutex_consistent.c10
-rw-r--r--src/thread/pthread_mutex_init.c2
-rw-r--r--src/thread/pthread_mutex_lock.c6
-rw-r--r--src/thread/pthread_mutex_timedlock.c3
-rw-r--r--src/thread/pthread_mutex_trylock.c38
-rw-r--r--src/thread/pthread_mutex_unlock.c13
-rw-r--r--src/thread/pthread_mutexattr_getrobust.c7
-rw-r--r--src/thread/pthread_mutexattr_setrobust.c9
10 files changed, 84 insertions, 10 deletions
diff --git a/include/pthread.h b/include/pthread.h
index d40002e6..e15f25bb 100644
--- a/include/pthread.h
+++ b/include/pthread.h
@@ -92,6 +92,7 @@ int pthread_mutex_unlock(pthread_mutex_t *);
 int pthread_mutex_trylock(pthread_mutex_t *);
 int pthread_mutex_timedlock(pthread_mutex_t *, const struct timespec *);
 int pthread_mutex_destroy(pthread_mutex_t *);
+int pthread_mutex_consistent(pthread_mutex_t *);
 
 int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *);
 int pthread_cond_destroy(pthread_cond_t *);
diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h
index 9d56e8fa..e3a9a0e0 100644
--- a/src/internal/pthread_impl.h
+++ b/src/internal/pthread_impl.h
@@ -37,6 +37,11 @@ struct pthread {
 	void **tsd;
 	pthread_attr_t attr;
 	volatile int dead;
+	struct {
+		void **head;
+		long off;
+		void *pending;
+	} robust_list;
 };
 
 #define __SU (sizeof(size_t)/sizeof(int))
diff --git a/src/thread/pthread_mutex_consistent.c b/src/thread/pthread_mutex_consistent.c
new file mode 100644
index 00000000..7dfb904f
--- /dev/null
+++ b/src/thread/pthread_mutex_consistent.c
@@ -0,0 +1,10 @@
+#include "pthread_impl.h"
+
+int pthread_mutex_consistent(pthread_mutex_t *m)
+{
+	if (m->_m_type < 8) return EINVAL;
+	if ((m->_m_lock & 0x3fffffff) != pthread_self()->tid)
+		return EPERM;
+	m->_m_type -= 8;
+	return 0;
+}
diff --git a/src/thread/pthread_mutex_init.c b/src/thread/pthread_mutex_init.c
index 6e23df13..75ddf02b 100644
--- a/src/thread/pthread_mutex_init.c
+++ b/src/thread/pthread_mutex_init.c
@@ -3,6 +3,6 @@
 int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a)
 {
 	memset(m, 0, sizeof *m);
-	if (a) m->_m_type = *a & 3;
+	if (a) m->_m_type = *a & 7;
 	return 0;
 }
diff --git a/src/thread/pthread_mutex_lock.c b/src/thread/pthread_mutex_lock.c
index 56111ec8..477b3d80 100644
--- a/src/thread/pthread_mutex_lock.c
+++ b/src/thread/pthread_mutex_lock.c
@@ -4,9 +4,9 @@ int pthread_mutex_lock(pthread_mutex_t *m)
 {
 	int r;
 	while ((r=pthread_mutex_trylock(m)) == EBUSY) {
-		if (!(r=m->_m_lock)) continue;
-		if (m->_m_type == PTHREAD_MUTEX_ERRORCHECK
-		 && r == pthread_self()->tid)
+		if (!(r=m->_m_lock) || (r&0x40000000)) continue;
+		if ((m->_m_type&3) == PTHREAD_MUTEX_ERRORCHECK
+		 && (r&0x1fffffff) == pthread_self()->tid)
 			return EDEADLK;
 		__wait(&m->_m_lock, &m->_m_waiters, r, 0);
 	}
diff --git a/src/thread/pthread_mutex_timedlock.c b/src/thread/pthread_mutex_timedlock.c
index 20ce0128..f1c3eed7 100644
--- a/src/thread/pthread_mutex_timedlock.c
+++ b/src/thread/pthread_mutex_timedlock.c
@@ -4,8 +4,9 @@ int pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *at)
 {
 	int r, w=0;
 	while ((r=pthread_mutex_trylock(m)) == EBUSY) {
+		if (!(r=m->_m_lock) || (r&0x40000000)) continue;
 		if (!w) a_inc(&m->_m_waiters), w++;
-		if (__timedwait(&m->_m_lock, 1, CLOCK_REALTIME, at, 0) == ETIMEDOUT) {
+		if (__timedwait(&m->_m_lock, r, CLOCK_REALTIME, at, 0) == ETIMEDOUT) {
 			if (w) a_dec(&m->_m_waiters);
 			return ETIMEDOUT;
 		}
diff --git a/src/thread/pthread_mutex_trylock.c b/src/thread/pthread_mutex_trylock.c
index de57ff9e..f48aaade 100644
--- a/src/thread/pthread_mutex_trylock.c
+++ b/src/thread/pthread_mutex_trylock.c
@@ -3,19 +3,51 @@
 int pthread_mutex_trylock(pthread_mutex_t *m)
 {
 	int tid;
+	int own;
+	pthread_t self;
 
 	if (m->_m_type == PTHREAD_MUTEX_NORMAL)
 		return (m->_m_lock || a_swap(&m->_m_lock, 1)) ? EBUSY : 0;
 
-	tid = pthread_self()->tid;
+	self = pthread_self();
+	tid = self->tid | 0x80000000;
 
-	if (m->_m_lock == tid && m->_m_type == PTHREAD_MUTEX_RECURSIVE) {
+	if (m->_m_type >= 4) {
+		if (!self->robust_list.off)
+			syscall2(__NR_set_robust_list,
+				(long)&self->robust_list, 3*sizeof(long));
+		self->robust_list.off = (char*)&m->_m_lock-(char *)&m->_m_next;
+		self->robust_list.pending = &m->_m_next;
+	}
+
+	if (m->_m_lock == tid && (m->_m_type&3) == PTHREAD_MUTEX_RECURSIVE) {
 		if ((unsigned)m->_m_count >= INT_MAX) return EAGAIN;
 		m->_m_count++;
 		return 0;
 	}
 
-	if (m->_m_lock || a_cas(&m->_m_lock, 0, tid)) return EBUSY;
+	own = m->_m_lock;
+	if ((own && !(own & 0x40000000)) || a_cas(&m->_m_lock, own, tid)!=own)
+		return EBUSY;
+
 	m->_m_count = 1;
+
+	if (m->_m_type < 4) return 0;
+
+	if (m->_m_type >= 8) {
+		m->_m_lock = 0;
+		return ENOTRECOVERABLE;
+	}
+	m->_m_next = self->robust_list.head;
+	m->_m_prev = &self->robust_list.head;
+	if (self->robust_list.head)
+		self->robust_list.head[-1] = &m->_m_next;
+	self->robust_list.head = &m->_m_next;
+	self->robust_list.pending = 0;
+	if (own) {
+		m->_m_type += 8;
+		return EOWNERDEAD;
+	}
+
 	return 0;
 }
diff --git a/src/thread/pthread_mutex_unlock.c b/src/thread/pthread_mutex_unlock.c
index 3733788d..67aa7ba5 100644
--- a/src/thread/pthread_mutex_unlock.c
+++ b/src/thread/pthread_mutex_unlock.c
@@ -2,14 +2,23 @@
 
 int pthread_mutex_unlock(pthread_mutex_t *m)
 {
+	pthread_t self;
+
 	if (m->_m_type != PTHREAD_MUTEX_NORMAL) {
-		if (!m->_m_lock || m->_m_lock != __pthread_self()->tid)
+		self = __pthread_self();
+		if ((m->_m_lock&0x1fffffff) != self->tid)
 		 	return EPERM;
-		if (m->_m_type == PTHREAD_MUTEX_RECURSIVE && --m->_m_count)
+		if ((m->_m_type&3) == PTHREAD_MUTEX_RECURSIVE && --m->_m_count)
 			return 0;
+		if (m->_m_type >= 4) {
+			self->robust_list.pending = &m->_m_next;
+			*(void **)m->_m_prev = m->_m_next;
+			if (m->_m_next) ((void **)m->_m_next)[-1] = m->_m_prev;
+		}
 	}
 
 	m->_m_lock = 0;
 	if (m->_m_waiters) __wake(&m->_m_lock, 1, 0);
+	if (m->_m_type >= 4) self->robust_list.pending = 0;
 	return 0;
 }
diff --git a/src/thread/pthread_mutexattr_getrobust.c b/src/thread/pthread_mutexattr_getrobust.c
new file mode 100644
index 00000000..b83cb7c6
--- /dev/null
+++ b/src/thread/pthread_mutexattr_getrobust.c
@@ -0,0 +1,7 @@
+#include "pthread_impl.h"
+
+int pthread_mutexattr_getrobust(const pthread_mutexattr_t *a, int *robust)
+{
+	*robust = *a / 4U % 2;
+	return 0;
+}
diff --git a/src/thread/pthread_mutexattr_setrobust.c b/src/thread/pthread_mutexattr_setrobust.c
new file mode 100644
index 00000000..4a296ba1
--- /dev/null
+++ b/src/thread/pthread_mutexattr_setrobust.c
@@ -0,0 +1,9 @@
+#include "pthread_impl.h"
+
+int pthread_mutexattr_setrobust(pthread_mutexattr_t *a, int robust)
+{
+	if (robust > 1U) return EINVAL;
+	*a &= ~4;
+	*a |= robust*4;
+	return 0;
+}