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 /src | |
parent | 2eff02e4a032323a45541c79967638d8c77d79e4 (diff) | |
download | musl-4b153ac42428447a148e6da543ebe6df017078db.tar.gz musl-4b153ac42428447a148e6da543ebe6df017078db.tar.bz2 musl-4b153ac42428447a148e6da543ebe6df017078db.tar.xz musl-4b153ac42428447a148e6da543ebe6df017078db.zip |
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...
Diffstat (limited to 'src')
-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; |