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.
---
 mingw-w64-libraries/winpthreads/src/cond.c | 46 +++++++++++++++++-----
 1 file changed, 37 insertions(+), 9 deletions(-)

diff --git a/mingw-w64-libraries/winpthreads/src/cond.c
b/mingw-w64-libraries/winpthreads/src/cond.c
index cd12c8b..725622d 100644
--- a/mingw-w64-libraries/winpthreads/src/cond.c
+++ b/mingw-w64-libraries/winpthreads/src/cond.c
@@ -431,9 +431,24 @@ pthread_cond_wait (pthread_cond_t *c, pthread_mutex_t
*external_mutex)
   } else if (_c->valid != (unsigned int)LIFE_COND)
     return EINVAL;
 
-  EnterCriticalSection (&_c->waiters_count_lock_);
+tryagain: r = do_sema_b_wait (_c->sema_b, 0,
INFINITE,&_c->waiters_b_lock_,&_c->value_b);
+  if (r != 0)
+    return r;
+
+  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);
+  if (r != 0)
+    return r;
 
   ch.c = _c;
   ch.r = &r;
@@ -479,22 +494,35 @@ pthread_cond_timedwait_impl (pthread_cond_t *c,
pthread_mutex_t *external_mutex,
     dwr = dwMilliSecs(_pthread_time_in_ms_from_timespec(t));
   }
 
-  EnterCriticalSection (&_c->waiters_count_lock_);
+tryagain: r = do_sema_b_wait (_c->sema_b, 0,
INFINITE,&_c->waiters_b_lock_,&_c->value_b);
+  if (r != 0)
+    return r;
+
+  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);
+  if (r != 0)
+    return r;
 
   ch.c = _c;
   ch.r = &r;
   ch.external_mutex = external_mutex;
-  {
-    pthread_cleanup_push(cleanup_wait, (void *) &ch);
 
-    r = pthread_mutex_unlock(external_mutex);
-    if (!r)
-      r = do_sema_b_wait (_c->sema_q, 0,
dwr,&_c->waiters_q_lock_,&_c->value_q);
+  pthread_cleanup_push(cleanup_wait, (void *) &ch);
+  r = pthread_mutex_unlock(external_mutex);
+  if (!r)
+    r = do_sema_b_wait (_c->sema_q, 0,
dwr,&_c->waiters_q_lock_,&_c->value_q);
+  pthread_cleanup_pop(1);
 
-    pthread_cleanup_pop(1);
-  }
   return r;
 }
 
-- 
2.22.0




_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to