From 1a821390d11d3bc66e6858f27dceeef67e14078d Mon Sep 17 00:00:00 2001 From: Aleksand Malikov Date: Mon, 23 Aug 2021 17:27:48 +0300 Subject: [PATCH] fix race condition in List_insert Revert mx parameter and mutex lock while operating the list. Mutex was removed with 94d24160 informing that: 'Use InterlockedCompareExchangePointer to ensure race safeness without using a mutex.' But it does not. Calling pthread_mutex_init and pthread_mutex_destroy from two or more threads occasionally leads to hang in pthread_mutex_destroy. To not change the behaviour of other cases where List_insert was called, List_insert_nolock is added. --- winsup/cygwin/thread.cc | 8 ++++---- winsup/cygwin/thread.h | 17 +++++++++++++++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 4d0ea274f..7c6a919c0 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -1595,7 +1595,7 @@ pthread_rwlock::add_reader () { RWLOCK_READER *rd = new RWLOCK_READER; if (rd) - List_insert (readers, rd); + List_insert_nolock (readers, rd); return rd; } @@ -2165,7 +2165,7 @@ pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void if (prepcb) { prepcb->cb = prepare; - List_insert (MT_INTERFACE->pthread_prepare, prepcb); + List_insert_nolock (MT_INTERFACE->pthread_prepare, prepcb); } if (parentcb) { @@ -2174,7 +2174,7 @@ pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void while (*t) t = &(*t)->next; /* t = pointer to last next in the list */ - List_insert (*t, parentcb); + List_insert_nolock (*t, parentcb); } if (childcb) { @@ -2183,7 +2183,7 @@ pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void while (*t) t = &(*t)->next; /* t = pointer to last next in the list */ - List_insert (*t, childcb); + List_insert_nolock (*t, childcb); } return 0; } diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h index 6b699ccb6..ddb2d7dbf 100644 --- a/winsup/cygwin/thread.h +++ b/winsup/cygwin/thread.h @@ -111,7 +111,20 @@ typedef enum } verifyable_object_state; template inline void -List_insert (list_node *&head, list_node *node) +List_insert (fast_mutex &mx, list_node *&head, list_node *node) +{ + if (!node) + return; + mx.lock (); + do + node->next = head; + while (InterlockedCompareExchangePointer ((PVOID volatile *) &head, + node, node->next) != node->next); + mx.unlock (); +} + +template inline void +List_insert_nolock (list_node *&head, list_node *node) { if (!node) return; @@ -163,7 +176,7 @@ template class List void insert (list_node *node) { - List_insert (head, node); + List_insert (mx, head, node); } void remove (list_node *node)