implement robust mutexes
authorRich Felker <dalias@aerifal.cx>
Fri, 18 Mar 2011 00:41:37 +0000 (20:41 -0400)
committerRich Felker <dalias@aerifal.cx>
Fri, 18 Mar 2011 00:41:37 +0000 (20:41 -0400)
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.

include/pthread.h
src/internal/pthread_impl.h
src/thread/pthread_mutex_consistent.c [new file with mode: 0644]
src/thread/pthread_mutex_init.c
src/thread/pthread_mutex_lock.c
src/thread/pthread_mutex_timedlock.c
src/thread/pthread_mutex_trylock.c
src/thread/pthread_mutex_unlock.c
src/thread/pthread_mutexattr_getrobust.c [new file with mode: 0644]
src/thread/pthread_mutexattr_setrobust.c [new file with mode: 0644]

index d40002e..e15f25b 100644 (file)
@@ -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_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 *);
 
 int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *);
 int pthread_cond_destroy(pthread_cond_t *);
index 9d56e8f..e3a9a0e 100644 (file)
@@ -37,6 +37,11 @@ struct pthread {
        void **tsd;
        pthread_attr_t attr;
        volatile int dead;
        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))
 };
 
 #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 (file)
index 0000000..7dfb904
--- /dev/null
@@ -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;
+}
index 6e23df1..75ddf02 100644 (file)
@@ -3,6 +3,6 @@
 int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a)
 {
        memset(m, 0, sizeof *m);
 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;
 }
        return 0;
 }
index 56111ec..477b3d8 100644 (file)
@@ -4,9 +4,9 @@ int pthread_mutex_lock(pthread_mutex_t *m)
 {
        int r;
        while ((r=pthread_mutex_trylock(m)) == EBUSY) {
 {
        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);
        }
                        return EDEADLK;
                __wait(&m->_m_lock, &m->_m_waiters, r, 0);
        }
index 20ce012..f1c3eed 100644 (file)
@@ -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) {
 {
        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 (!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;
                }
                        if (w) a_dec(&m->_m_waiters);
                        return ETIMEDOUT;
                }
index de57ff9..f48aaad 100644 (file)
@@ -3,19 +3,51 @@
 int pthread_mutex_trylock(pthread_mutex_t *m)
 {
        int tid;
 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;
 
 
        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 ((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;
        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;
 }
        return 0;
 }
index 3733788..67aa7ba 100644 (file)
@@ -2,14 +2,23 @@
 
 int pthread_mutex_unlock(pthread_mutex_t *m)
 {
 
 int pthread_mutex_unlock(pthread_mutex_t *m)
 {
+       pthread_t self;
+
        if (m->_m_type != PTHREAD_MUTEX_NORMAL) {
        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;
                        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;
                        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);
        }
 
        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;
 }
        return 0;
 }
diff --git a/src/thread/pthread_mutexattr_getrobust.c b/src/thread/pthread_mutexattr_getrobust.c
new file mode 100644 (file)
index 0000000..b83cb7c
--- /dev/null
@@ -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 (file)
index 0000000..4a296ba
--- /dev/null
@@ -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;
+}