From 330025c54b85512d54b6960fad07498365c8fee3 Mon Sep 17 00:00:00 2001 From: xnor Date: Mon, 12 Aug 2019 17:27:17 +0000 Subject: [PATCH] Wait on sema_b again to ensure pthread_cond_wait() functions atomically as required by POSIX. Since holding sema_b before aquiring waiters_count_lock_ can lead to deadlocks try to aquire waiters_count_lock_ opportunistically. If it fails then release sema_b and sched_yield() to give the other thread (which has aquired waiters_count_lock_ and is now waiting on sema_b) a chance to aquire sema_b before we retry the whole procedure. Signed-off-by: Liu Hao --- mingw-w64-libraries/winpthreads/src/cond.c | 24 ++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/mingw-w64-libraries/winpthreads/src/cond.c b/mingw-w64-libraries/winpthreads/src/cond.c index 8df395ebf..d50f85b40 100644 --- a/mingw-w64-libraries/winpthreads/src/cond.c +++ b/mingw-w64-libraries/winpthreads/src/cond.c @@ -431,10 +431,20 @@ pthread_cond_wait (pthread_cond_t *c, pthread_mutex_t *external_mutex) } else if (_c->valid != (unsigned int)LIFE_COND) return EINVAL; +tryagain: r = do_sema_b_wait (_c->sema_b, 0, INFINITE,&_c->waiters_b_lock_,&_c->value_b); if (r != 0) return r; - EnterCriticalSection (&_c->waiters_count_lock_); + + if (!TryEnterCriticalSection (&_c->waiters_count_lock_)) + { + r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b); + if (r != 0) + return r; + sched_yield(); + goto tryagain; + } + _c->waiters_count_++; LeaveCriticalSection(&_c->waiters_count_lock_); r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b); @@ -485,10 +495,20 @@ pthread_cond_timedwait_impl (pthread_cond_t *c, pthread_mutex_t *external_mutex, dwr = dwMilliSecs(_pthread_time_in_ms_from_timespec(t)); } +tryagain: r = do_sema_b_wait (_c->sema_b, 0, INFINITE,&_c->waiters_b_lock_,&_c->value_b); if (r != 0) return r; - EnterCriticalSection (&_c->waiters_count_lock_); + + if (!TryEnterCriticalSection (&_c->waiters_count_lock_)) + { + r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b); + if (r != 0) + return r; + sched_yield(); + goto tryagain; + } + _c->waiters_count_++; LeaveCriticalSection(&_c->waiters_count_lock_); r = do_sema_b_release (_c->sema_b, 1,&_c->waiters_b_lock_,&_c->value_b);