diff options
| author | Rich Felker <dalias@aerifal.cx> | 2011-09-22 21:08:55 -0400 | 
|---|---|---|
| committer | Rich Felker <dalias@aerifal.cx> | 2011-09-22 21:08:55 -0400 | 
| commit | 4b153ac42428447a148e6da543ebe6df017078db (patch) | |
| tree | d9a5b8035f98b8cec47fc6044e38305ea5cdb91a | |
| parent | 2eff02e4a032323a45541c79967638d8c77d79e4 (diff) | |
| download | musl-4b153ac42428447a148e6da543ebe6df017078db.tar.gz | |
fix deadlock in condition wait whenever there are multiple waiters
it's amazing none of the conformance tests i've run even bothered to
check whether something so basic works...
| -rw-r--r-- | src/internal/pthread_impl.h | 1 | ||||
| -rw-r--r-- | src/thread/pthread_cond_broadcast.c | 3 | ||||
| -rw-r--r-- | src/thread/pthread_cond_signal.c | 3 | ||||
| -rw-r--r-- | src/thread/pthread_cond_timedwait.c | 16 | 
4 files changed, 18 insertions, 5 deletions
| diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h index 26164d83..d123e5e3 100644 --- a/src/internal/pthread_impl.h +++ b/src/internal/pthread_impl.h @@ -66,6 +66,7 @@ struct __timer {  #define _m_count __u.__i[5]  #define _c_block __u.__i[0]  #define _c_clock __u.__i[1] +#define _c_waiters __u.__i[2]  #define _rw_lock __u.__i[0]  #define _rw_waiters __u.__i[1]  #define _b_inst __u.__p[0] diff --git a/src/thread/pthread_cond_broadcast.c b/src/thread/pthread_cond_broadcast.c index 30f7f6df..6002c535 100644 --- a/src/thread/pthread_cond_broadcast.c +++ b/src/thread/pthread_cond_broadcast.c @@ -2,7 +2,8 @@  int pthread_cond_broadcast(pthread_cond_t *c)  { -	if (a_swap(&c->_c_block, 0)) +	int w = c->_c_waiters; +	if (a_swap(&c->_c_block, 0) || w)  		__wake(&c->_c_block, -1, 0);  	return 0;  } diff --git a/src/thread/pthread_cond_signal.c b/src/thread/pthread_cond_signal.c index a0211287..e8ed71cc 100644 --- a/src/thread/pthread_cond_signal.c +++ b/src/thread/pthread_cond_signal.c @@ -2,7 +2,8 @@  int pthread_cond_signal(pthread_cond_t *c)  { -	if (a_swap(&c->_c_block, 0)); +	int w = c->_c_waiters; +	if (a_swap(&c->_c_block, 0) || w)  		__wake(&c->_c_block, 1, 0);  	return 0;  } diff --git a/src/thread/pthread_cond_timedwait.c b/src/thread/pthread_cond_timedwait.c index ee874a36..ec5aa6f4 100644 --- a/src/thread/pthread_cond_timedwait.c +++ b/src/thread/pthread_cond_timedwait.c @@ -1,12 +1,20 @@  #include "pthread_impl.h" -static void relock(void *m) +struct cm { +	pthread_cond_t *c; +	pthread_mutex_t *m; +}; + +static void cleanup(void *p)  { -	pthread_mutex_lock(m); +	struct cm *cm = p; +	a_dec(&cm->c->_c_waiters); +	pthread_mutex_lock(cm->m);  }  int pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m, const struct timespec *ts)  { +	struct cm cm = { .c=c, .m=m };  	int r, e=0;  	if (ts && ts->tv_nsec >= 1000000000UL) @@ -17,8 +25,10 @@ int pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m, const struct t  	c->_c_block = 1;  	if ((r=pthread_mutex_unlock(m))) return r; -	do e = __timedwait(&c->_c_block, 1, c->_c_clock, ts, relock, m, 0); +	a_inc(&c->_c_waiters); +	do e = __timedwait(&c->_c_block, 1, c->_c_clock, ts, cleanup, &cm, 0);  	while (e == EINTR); +	a_dec(&c->_c_waiters);  	if ((r=pthread_mutex_lock(m))) return r; | 
