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