Skip to content

Commit

Permalink
Replace global Critical Sections with MCS Queue locks
Browse files Browse the repository at this point in the history
  • Loading branch information
rpj committed Mar 10, 2011
1 parent 46b13ac commit 7b055a3
Show file tree
Hide file tree
Showing 21 changed files with 95 additions and 134 deletions.
23 changes: 23 additions & 0 deletions ChangeLog
@@ -1,3 +1,26 @@
2011-03-09 Ross Johnson <ross.johnson at homemail.com.au>

* implement.h (ptw32_thread_t_): Add process unique sequence number.
* global.c: Replace global Critical Section objects with MCS
queue locks.
* implement.h: Likewise.
* pthread_cond_destroy.c: Likewise.
* pthread_cond_init.c: Likewise.
* pthread_detach.c: Likewise.
* pthread_join.c: Likewise.
* pthread_kill.c: Likewise.
* pthread_mutex_destroy.c: Likewise.
* pthread_rwlock_destroy.c: Likewise.
* pthread_spin_destroy.c: Likewise.
* pthread_timechange_handler_np.c: Likewise.
* ptw32_cond_check_need_init.c: Likewise.
* ptw32_mutex_check_need_init.c: Likewise.
* ptw32_processInitialize.c: Likewise.
* ptw32_processTerminate.c: Likewise.
* ptw32_reuse.c: Likewise.
* ptw32_rwlock_check_need_init.c: Likewise.
* ptw32_spinlock_check_need_init.c: Likewise.

2011-03-06 Ross Johnson <ross.johnson at homemail.com.au>

* several (MINGW64): Cast and call fixups for 64 bit compatibility;
Expand Down
12 changes: 6 additions & 6 deletions global.c
Expand Up @@ -62,37 +62,37 @@ DWORD (*ptw32_register_cancelation) (PAPCFUNC, HANDLE, DWORD) = NULL;
/*
* Global lock for managing pthread_t struct reuse.
*/
CRITICAL_SECTION ptw32_thread_reuse_lock;
ptw32_mcs_lock_t ptw32_thread_reuse_lock;

/*
* Global lock for testing internal state of statically declared mutexes.
*/
CRITICAL_SECTION ptw32_mutex_test_init_lock;
ptw32_mcs_lock_t ptw32_mutex_test_init_lock;

/*
* Global lock for testing internal state of PTHREAD_COND_INITIALIZER
* created condition variables.
*/
CRITICAL_SECTION ptw32_cond_test_init_lock;
ptw32_mcs_lock_t ptw32_cond_test_init_lock;

/*
* Global lock for testing internal state of PTHREAD_RWLOCK_INITIALIZER
* created read/write locks.
*/
CRITICAL_SECTION ptw32_rwlock_test_init_lock;
ptw32_mcs_lock_t ptw32_rwlock_test_init_lock;

/*
* Global lock for testing internal state of PTHREAD_SPINLOCK_INITIALIZER
* created spin locks.
*/
CRITICAL_SECTION ptw32_spinlock_test_init_lock;
ptw32_mcs_lock_t ptw32_spinlock_test_init_lock;

/*
* Global lock for condition variable linked list. The list exists
* to wake up CVs when a WM_TIMECHANGE message arrives. See
* w32_TimeChangeHandler.c.
*/
CRITICAL_SECTION ptw32_cond_list_lock;
ptw32_mcs_lock_t ptw32_cond_list_lock;

#ifdef _UWIN
/*
Expand Down
15 changes: 8 additions & 7 deletions implement.h
Expand Up @@ -131,7 +131,8 @@ struct ptw32_thread_t_
#ifdef _UWIN
DWORD dummy[5];
#endif
DWORD thread;
UINT64 seqNumber; /* Process-unique thread sequence number */
DWORD thread; /* Win32 thread ID */
HANDLE threadH; /* Win32 thread handle - POSIX thread is invalid if threadH == 0 */
pthread_t ptHandle; /* This thread's permanent pthread_t handle */
ptw32_thread_t * prevReuse; /* Links threads on reuse stack */
Expand Down Expand Up @@ -535,12 +536,12 @@ extern int ptw32_concurrency;

extern int ptw32_features;

extern CRITICAL_SECTION ptw32_thread_reuse_lock;
extern CRITICAL_SECTION ptw32_mutex_test_init_lock;
extern CRITICAL_SECTION ptw32_cond_list_lock;
extern CRITICAL_SECTION ptw32_cond_test_init_lock;
extern CRITICAL_SECTION ptw32_rwlock_test_init_lock;
extern CRITICAL_SECTION ptw32_spinlock_test_init_lock;
extern ptw32_mcs_lock_t ptw32_thread_reuse_lock;
extern ptw32_mcs_lock_t ptw32_mutex_test_init_lock;
extern ptw32_mcs_lock_t ptw32_cond_list_lock;
extern ptw32_mcs_lock_t ptw32_cond_test_init_lock;
extern ptw32_mcs_lock_t ptw32_rwlock_test_init_lock;
extern ptw32_mcs_lock_t ptw32_spinlock_test_init_lock;

#ifdef _UWIN
extern int pthread_count;
Expand Down
12 changes: 7 additions & 5 deletions pthread_cond_destroy.c
Expand Up @@ -126,7 +126,8 @@ pthread_cond_destroy (pthread_cond_t * cond)

if (*cond != PTHREAD_COND_INITIALIZER)
{
EnterCriticalSection (&ptw32_cond_list_lock);
ptw32_mcs_local_node_t node;
ptw32_mcs_lock_acquire(&ptw32_cond_list_lock, &node);

cv = *cond;

Expand Down Expand Up @@ -154,7 +155,7 @@ pthread_cond_destroy (pthread_cond_t * cond)

if (result != 0)
{
LeaveCriticalSection (&ptw32_cond_list_lock);
ptw32_mcs_lock_release(&node);
return result;
}

Expand Down Expand Up @@ -213,14 +214,15 @@ pthread_cond_destroy (pthread_cond_t * cond)
(void) free (cv);
}

LeaveCriticalSection (&ptw32_cond_list_lock);
ptw32_mcs_lock_release(&node);
}
else
{
ptw32_mcs_local_node_t node;
/*
* See notes in ptw32_cond_check_need_init() above also.
*/
EnterCriticalSection (&ptw32_cond_test_init_lock);
ptw32_mcs_lock_acquire(&ptw32_cond_test_init_lock, &node);

/*
* Check again.
Expand All @@ -244,7 +246,7 @@ pthread_cond_destroy (pthread_cond_t * cond)
result = EBUSY;
}

LeaveCriticalSection (&ptw32_cond_test_init_lock);
ptw32_mcs_lock_release(&node);
}

return ((result != 0) ? result : ((result1 != 0) ? result1 : result2));
Expand Down
6 changes: 4 additions & 2 deletions pthread_cond_init.c
Expand Up @@ -138,7 +138,9 @@ pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
DONE:
if (0 == result)
{
EnterCriticalSection (&ptw32_cond_list_lock);
ptw32_mcs_local_node_t node;

ptw32_mcs_lock_acquire(&ptw32_cond_list_lock, &node);

cv->next = NULL;
cv->prev = ptw32_cond_list_tail;
Expand All @@ -155,7 +157,7 @@ pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
ptw32_cond_list_head = cv;
}

LeaveCriticalSection (&ptw32_cond_list_lock);
ptw32_mcs_lock_release(&node);
}

*cond = cv;
Expand Down
5 changes: 3 additions & 2 deletions pthread_detach.c
Expand Up @@ -77,8 +77,9 @@ pthread_detach (pthread_t thread)
int result;
BOOL destroyIt = PTW32_FALSE;
ptw32_thread_t * tp = (ptw32_thread_t *) thread.p;
ptw32_mcs_local_node_t node;

EnterCriticalSection (&ptw32_thread_reuse_lock);
ptw32_mcs_lock_acquire(&ptw32_thread_reuse_lock, &node);

if (NULL == tp
|| thread.x != tp->ptHandle.x)
Expand Down Expand Up @@ -120,7 +121,7 @@ pthread_detach (pthread_t thread)
}
}

LeaveCriticalSection (&ptw32_thread_reuse_lock);
ptw32_mcs_lock_release(&node);

if (result == 0)
{
Expand Down
5 changes: 3 additions & 2 deletions pthread_join.c
Expand Up @@ -85,8 +85,9 @@ pthread_join (pthread_t thread, void **value_ptr)
int result;
pthread_t self;
ptw32_thread_t * tp = (ptw32_thread_t *) thread.p;
ptw32_mcs_local_node_t node;

EnterCriticalSection (&ptw32_thread_reuse_lock);
ptw32_mcs_lock_acquire(&ptw32_thread_reuse_lock, &node);

if (NULL == tp
|| thread.x != tp->ptHandle.x)
Expand All @@ -102,7 +103,7 @@ pthread_join (pthread_t thread, void **value_ptr)
result = 0;
}

LeaveCriticalSection (&ptw32_thread_reuse_lock);
ptw32_mcs_lock_release(&node);

if (result == 0)
{
Expand Down
5 changes: 3 additions & 2 deletions pthread_kill.c
Expand Up @@ -77,8 +77,9 @@ pthread_kill (pthread_t thread, int sig)
{
int result = 0;
ptw32_thread_t * tp;
ptw32_mcs_local_node_t node;

EnterCriticalSection (&ptw32_thread_reuse_lock);
ptw32_mcs_lock_acquire(&ptw32_thread_reuse_lock, &node);

tp = (ptw32_thread_t *) thread.p;

Expand All @@ -89,7 +90,7 @@ pthread_kill (pthread_t thread, int sig)
result = ESRCH;
}

LeaveCriticalSection (&ptw32_thread_reuse_lock);
ptw32_mcs_lock_release(&node);

if (0 == result && 0 != sig)
{
Expand Down
12 changes: 5 additions & 7 deletions pthread_mutex_destroy.c
Expand Up @@ -71,10 +71,6 @@ pthread_mutex_destroy (pthread_mutex_t * mutex)
* be too late invalidating the mutex below since another thread
* may already have entered mutex_lock and the check for a valid
* *mutex != NULL.
*
* Note that this would be an unusual situation because it is not
* common that mutexes are destroyed while they are still in
* use by other threads.
*/
*mutex = NULL;

Expand Down Expand Up @@ -112,10 +108,13 @@ pthread_mutex_destroy (pthread_mutex_t * mutex)
}
else
{
ptw32_mcs_local_node_t node;

/*
* See notes in ptw32_mutex_check_need_init() above also.
*/
EnterCriticalSection (&ptw32_mutex_test_init_lock);

ptw32_mcs_lock_acquire(&ptw32_mutex_test_init_lock, &node);

/*
* Check again.
Expand All @@ -138,8 +137,7 @@ pthread_mutex_destroy (pthread_mutex_t * mutex)
*/
result = EBUSY;
}

LeaveCriticalSection (&ptw32_mutex_test_init_lock);
ptw32_mcs_lock_release(&node);
}

return (result);
Expand Down
5 changes: 3 additions & 2 deletions pthread_rwlock_destroy.c
Expand Up @@ -108,10 +108,11 @@ pthread_rwlock_destroy (pthread_rwlock_t * rwlock)
}
else
{
ptw32_mcs_local_node_t node;
/*
* See notes in ptw32_rwlock_check_need_init() above also.
*/
EnterCriticalSection (&ptw32_rwlock_test_init_lock);
ptw32_mcs_lock_acquire(&ptw32_rwlock_test_init_lock, &node);

/*
* Check again.
Expand All @@ -135,7 +136,7 @@ pthread_rwlock_destroy (pthread_rwlock_t * rwlock)
result = EBUSY;
}

LeaveCriticalSection (&ptw32_rwlock_test_init_lock);
ptw32_mcs_lock_release(&node);
}

return ((result != 0) ? result : ((result1 != 0) ? result1 : result2));
Expand Down
6 changes: 4 additions & 2 deletions pthread_spin_destroy.c
Expand Up @@ -81,7 +81,9 @@ pthread_spin_destroy (pthread_spinlock_t * lock)
/*
* See notes in ptw32_spinlock_check_need_init() above also.
*/
EnterCriticalSection (&ptw32_spinlock_test_init_lock);
ptw32_mcs_local_node_t node;

ptw32_mcs_lock_acquire(&ptw32_spinlock_test_init_lock, &node);

/*
* Check again.
Expand All @@ -105,7 +107,7 @@ pthread_spin_destroy (pthread_spinlock_t * lock)
result = EBUSY;
}

LeaveCriticalSection (&ptw32_spinlock_test_init_lock);
ptw32_mcs_lock_release(&node);
}

return (result);
Expand Down
5 changes: 3 additions & 2 deletions pthread_timechange_handler_np.c
Expand Up @@ -90,8 +90,9 @@ pthread_timechange_handler_np (void *arg)
{
int result = 0;
pthread_cond_t cv;
ptw32_mcs_local_node_t node;

EnterCriticalSection (&ptw32_cond_list_lock);
ptw32_mcs_lock_acquire(&ptw32_cond_list_lock, &node);

cv = ptw32_cond_list_head;

Expand All @@ -101,7 +102,7 @@ pthread_timechange_handler_np (void *arg)
cv = cv->next;
}

LeaveCriticalSection (&ptw32_cond_list_lock);
ptw32_mcs_lock_release(&node);

return (void *) (size_t) (result != 0 ? EAGAIN : 0);
}
22 changes: 3 additions & 19 deletions ptw32_cond_check_need_init.c
Expand Up @@ -43,29 +43,13 @@ INLINE int
ptw32_cond_check_need_init (pthread_cond_t * cond)
{
int result = 0;
ptw32_mcs_local_node_t node;

/*
* The following guarded test is specifically for statically
* initialised condition variables (via PTHREAD_OBJECT_INITIALIZER).
*
* Note that by not providing this synchronisation we risk
* introducing race conditions into applications which are
* correctly written.
*
* Approach
* --------
* We know that static condition variables will not be PROCESS_SHARED
* so we can serialise access to internal state using
* Win32 Critical Sections rather than Win32 Mutexes.
*
* If using a single global lock slows applications down too much,
* multiple global locks could be created and hashed on some random
* value associated with each mutex, the pointer perhaps. At a guess,
* a good value for the optimal number of global locks might be
* the number of processors + 1.
*
*/
EnterCriticalSection (&ptw32_cond_test_init_lock);
ptw32_mcs_lock_acquire(&ptw32_cond_test_init_lock, &node);

/*
* We got here possibly under race
Expand All @@ -88,7 +72,7 @@ ptw32_cond_check_need_init (pthread_cond_t * cond)
result = EINVAL;
}

LeaveCriticalSection (&ptw32_cond_test_init_lock);
ptw32_mcs_lock_release(&node);

return result;
}

0 comments on commit 7b055a3

Please sign in to comment.