summaryrefslogtreecommitdiff
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;
+}