about summary refs log tree commit diff
diff options
context:
space:
mode:
-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;
+}