diff options
-rw-r--r-- | include/pthread.h | 1 | ||||
-rw-r--r-- | src/internal/pthread_impl.h | 5 | ||||
-rw-r--r-- | src/thread/pthread_mutex_consistent.c | 10 | ||||
-rw-r--r-- | src/thread/pthread_mutex_init.c | 2 | ||||
-rw-r--r-- | src/thread/pthread_mutex_lock.c | 6 | ||||
-rw-r--r-- | src/thread/pthread_mutex_timedlock.c | 3 | ||||
-rw-r--r-- | src/thread/pthread_mutex_trylock.c | 38 | ||||
-rw-r--r-- | src/thread/pthread_mutex_unlock.c | 13 | ||||
-rw-r--r-- | src/thread/pthread_mutexattr_getrobust.c | 7 | ||||
-rw-r--r-- | src/thread/pthread_mutexattr_setrobust.c | 9 |
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; +} |