From db171f2f9435b98f05f33fcbc0dcf0c5cc1cb917 Mon Sep 17 00:00:00 2001 From: rpj Date: Thu, 24 Mar 2011 23:33:14 +0000 Subject: First pass of robust mutexes --- Bmakefile | 5 +- GNUmakefile | 8 +- Makefile | 8 +- README.NONPORTABLE | 20 ++- create.c | 79 ++++++------ global.c | 12 +- implement.h | 81 ++++++++---- mutex.c | 3 + need_errno.h | 4 + pthread.h | 39 ++++-- pthread_barrier_destroy.c | 2 +- pthread_barrier_wait.c | 2 +- pthread_cancel.c | 9 +- pthread_delay_np.c | 7 +- pthread_detach.c | 34 +++--- pthread_key_create.c | 2 +- pthread_key_delete.c | 40 +++--- pthread_mutex_destroy.c | 10 +- pthread_mutex_init.c | 53 ++++++-- pthread_mutex_lock.c | 258 +++++++++++++++++++++++++++++++-------- pthread_mutex_timedlock.c | 240 +++++++++++++++++++++++++++++------- pthread_mutex_trylock.c | 106 +++++++++++++--- pthread_mutex_unlock.c | 158 +++++++++++++++++------- pthread_setcancelstate.c | 7 +- pthread_setcanceltype.c | 7 +- pthread_setschedparam.c | 34 +++--- pthread_setspecific.c | 55 ++++----- pthread_testcancel.c | 7 +- pthread_win32_attach_detach_np.c | 28 ++++- ptw32_MCS_lock.c | 14 +-- ptw32_callUserDestroyRoutines.c | 24 ++-- ptw32_new.c | 6 +- ptw32_reuse.c | 2 + ptw32_threadDestroy.c | 3 - ptw32_threadStart.c | 19 +-- ptw32_throw.c | 2 + ptw32_tkAssocCreate.c | 2 +- ptw32_tkAssocDestroy.c | 2 +- tests/Bmakefile | 6 + tests/ChangeLog | 15 +++ tests/GNUmakefile | 17 ++- tests/Makefile | 7 ++ tests/SIZES.GC | 6 +- tests/SIZES.VC | 6 +- tests/Wmakefile | 6 + tests/benchtest1.c | 24 +++- tests/benchtest2.c | 26 +++- tests/benchtest3.c | 24 +++- tests/benchtest4.c | 24 +++- tests/cancel6d.c | 5 +- tests/mutex1e.c | 4 + tests/mutex1n.c | 4 + tests/mutex1r.c | 4 + tests/mutex4.c | 22 ++-- tests/mutex6e.c | 9 +- tests/mutex6n.c | 21 ++-- tests/mutex6r.c | 9 +- tests/mutex7.c | 2 +- tests/mutex7e.c | 10 +- tests/mutex7n.c | 13 +- tests/mutex7r.c | 9 +- tests/mutex8e.c | 8 +- tests/mutex8n.c | 8 +- tests/mutex8r.c | 8 +- tests/test.h | 26 +++- w32_CancelableWait.c | 7 +- 66 files changed, 1248 insertions(+), 474 deletions(-) diff --git a/Bmakefile b/Bmakefile index 300cefd..38aa61d 100644 --- a/Bmakefile +++ b/Bmakefile @@ -116,10 +116,13 @@ MUTEX_SRCS = \ pthread_mutexattr_setpshared.c \ pthread_mutexattr_settype.c \ pthread_mutexattr_gettype.c \ + pthread_mutexattr_setrobust.c \ + pthread_mutexattr_getrobust.c \ pthread_mutex_lock.c \ pthread_mutex_timedlock.c \ pthread_mutex_unlock.c \ - pthread_mutex_trylock.c + pthread_mutex_trylock.c \ + pthread_mutex_consistent.c NONPORTABLE_SRCS = \ pthread_mutexattr_setkind_np.c \ diff --git a/GNUmakefile b/GNUmakefile index b357c39..40fd538 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -184,10 +184,13 @@ SMALL_STATIC_OBJS = \ pthread_mutexattr_setpshared.o \ pthread_mutexattr_settype.o \ pthread_mutexattr_gettype.o \ + pthread_mutexattr_setrobust.o \ + pthread_mutexattr_getrobust.o \ pthread_mutex_lock.o \ pthread_mutex_timedlock.o \ pthread_mutex_unlock.o \ pthread_mutex_trylock.o \ + pthread_mutex_consistent.o \ pthread_mutexattr_setkind_np.o \ pthread_mutexattr_getkind_np.o \ pthread_getw32threadhandle_np.o \ @@ -338,10 +341,13 @@ MUTEX_SRCS = \ pthread_mutexattr_setpshared.c \ pthread_mutexattr_settype.c \ pthread_mutexattr_gettype.c \ + pthread_mutexattr_setrobust.c \ + pthread_mutexattr_getrobust.c \ pthread_mutex_lock.c \ pthread_mutex_timedlock.c \ pthread_mutex_unlock.c \ - pthread_mutex_trylock.c + pthread_mutex_trylock.c \ + pthread_mutex_consistent.c NONPORTABLE_SRCS = \ pthread_mutexattr_setkind_np.c \ diff --git a/Makefile b/Makefile index 4b790c0..23ef981 100644 --- a/Makefile +++ b/Makefile @@ -130,10 +130,13 @@ SMALL_STATIC_OBJS = \ pthread_mutexattr_setpshared.obj \ pthread_mutexattr_settype.obj \ pthread_mutexattr_gettype.obj \ + pthread_mutexattr_setrobust.obj \ + pthread_mutexattr_getrobust.obj \ pthread_mutex_lock.obj \ pthread_mutex_timedlock.obj \ pthread_mutex_unlock.obj \ pthread_mutex_trylock.obj \ + pthread_mutex_consistent.obj \ pthread_mutexattr_setkind_np.obj \ pthread_mutexattr_getkind_np.obj \ pthread_getw32threadhandle_np.obj \ @@ -280,10 +283,13 @@ MUTEX_SRCS = \ pthread_mutexattr_setpshared.c \ pthread_mutexattr_settype.c \ pthread_mutexattr_gettype.c \ + pthread_mutexattr_setrobust.c \ + pthread_mutexattr_getrobust.c \ pthread_mutex_lock.c \ pthread_mutex_timedlock.c \ pthread_mutex_unlock.c \ - pthread_mutex_trylock.c + pthread_mutex_trylock.c \ + pthread_mutex_consistent.c NONPORTABLE_SRCS = \ pthread_mutexattr_setkind_np.c \ diff --git a/README.NONPORTABLE b/README.NONPORTABLE index 35ff44f..e25fc50 100644 --- a/README.NONPORTABLE +++ b/README.NONPORTABLE @@ -347,8 +347,6 @@ rewritten.] Doesn't the compiler take care of padding? -Answer a question with two questions: Which compiler? Which language? - The C89 and later standards only effectively guarrantee element-by-element equivalence following an assignment or pass by value of a struct or union, therefore undefined areas of any two otherwise equivalent pthread_t instances @@ -396,11 +394,10 @@ pthread_null() pthread_compare() pthread_hash() -However these are very specific and are unlikely to make it into the -standard. A signle more general purpose function can be defined as a -basis for all three of the above functions. +A single more general purpose function could also be defined as a +basis for at least the last two of the above functions. -But first we need to list the freedoms and constraints with restpect +First we need to list the freedoms and constraints with restpect to pthread_t so that we can be sure our solution is compatible with the standard. @@ -414,13 +411,10 @@ itself. at compile-time and size-invariant, because it must be able to copy the object (i.e. through assignment and pass-by-value). Such copies must be genuine duplicates, not merely a copy of a pointer to a common instance such as -would be the case if pthread_t were defined as an array. There is evidence that -this is or was the intention also in the rationale, where it expects that -pthread_t is hashable, and that is only possible if the application can -determine the size of pthread_t (e.g. via sizeof() in C). +would be the case if pthread_t were defined as an array. -The following candidate function is proposed +Suppose we define the following function: /* This function shall return it's argument */ pthread_t* pthread_normalize(pthread_t* thread); @@ -446,7 +440,7 @@ Advantages: 1) In most existing implementations this function would reduce to a no-op that emits no additional instructions, i.e after in-lining or optimisation, or if defined as a macro: -#define pthread_normalise(tptr) tptr +#define pthread_normalise(tptr) (tptr) 2) This single function allows an application to portably derive application-level versions of any of the other required functions. @@ -633,7 +627,7 @@ t = null_tid; Note that we don't have to explicitly make use of the __size array at all. It's -there just to alter the semantics of the compiler. +there just to force the compiler behaviour we want. Partial solutions without a pthread_normalize function diff --git a/create.c b/create.c index dfc6967..a67d227 100644 --- a/create.c +++ b/create.c @@ -227,44 +227,47 @@ pthread_create (pthread_t * tid, #else - /* - * This lock will force pthread_threadStart() to wait until we have - * the thread handle and have set the priority. - */ - (void) pthread_mutex_lock (&tp->cancelLock); - - tp->threadH = - threadH = - (HANDLE) _beginthread (ptw32_threadStart, (unsigned) stackSize, /* default stack size */ - parms); - - /* - * Make the return code match _beginthreadex's. - */ - if (threadH == (HANDLE) - 1L) - { - tp->threadH = threadH = 0; - } - else - { - if (!run) - { - /* - * beginthread does not allow for create flags, so we do it now. - * Note that beginthread itself creates the thread in SUSPENDED - * mode, and then calls ResumeThread to start it. - */ - SuspendThread (threadH); - } - - if (a != NULL) - { - (void) ptw32_setthreadpriority (thread, SCHED_OTHER, priority); - } - } - - (void) pthread_mutex_unlock (&tp->cancelLock); - + { + ptw32_mcs_local_node_t stateLock; + + /* + * This lock will force pthread_threadStart() to wait until we have + * the thread handle and have set the priority. + */ + ptw32_mcs_lock_acquire(&tp->stateLock, &stateLock); + + tp->threadH = + threadH = + (HANDLE) _beginthread (ptw32_threadStart, (unsigned) stackSize, /* default stack size */ + parms); + + /* + * Make the return code match _beginthreadex's. + */ + if (threadH == (HANDLE) - 1L) + { + tp->threadH = threadH = 0; + } + else + { + if (!run) + { + /* + * beginthread does not allow for create flags, so we do it now. + * Note that beginthread itself creates the thread in SUSPENDED + * mode, and then calls ResumeThread to start it. + */ + SuspendThread (threadH); + } + + if (a != NULL) + { + (void) ptw32_setthreadpriority (thread, SCHED_OTHER, priority); + } + } + + ptw32_mcs_lock_release (&stateLock); + } #endif result = (threadH != 0) ? 0 : EAGAIN; diff --git a/global.c b/global.c index df4806b..be6d027 100644 --- a/global.c +++ b/global.c @@ -62,37 +62,37 @@ DWORD (*ptw32_register_cancelation) (PAPCFUNC, HANDLE, DWORD) = NULL; /* * Global lock for managing pthread_t struct reuse. */ -ptw32_mcs_lock_t ptw32_thread_reuse_lock; +ptw32_mcs_lock_t ptw32_thread_reuse_lock = 0; /* * Global lock for testing internal state of statically declared mutexes. */ -ptw32_mcs_lock_t ptw32_mutex_test_init_lock; +ptw32_mcs_lock_t ptw32_mutex_test_init_lock = 0; /* * Global lock for testing internal state of PTHREAD_COND_INITIALIZER * created condition variables. */ -ptw32_mcs_lock_t ptw32_cond_test_init_lock; +ptw32_mcs_lock_t ptw32_cond_test_init_lock = 0; /* * Global lock for testing internal state of PTHREAD_RWLOCK_INITIALIZER * created read/write locks. */ -ptw32_mcs_lock_t ptw32_rwlock_test_init_lock; +ptw32_mcs_lock_t ptw32_rwlock_test_init_lock = 0; /* * Global lock for testing internal state of PTHREAD_SPINLOCK_INITIALIZER * created spin locks. */ -ptw32_mcs_lock_t ptw32_spinlock_test_init_lock; +ptw32_mcs_lock_t ptw32_spinlock_test_init_lock = 0; /* * Global lock for condition variable linked list. The list exists * to wake up CVs when a WM_TIMECHANGE message arrives. See * w32_TimeChangeHandler.c. */ -ptw32_mcs_lock_t ptw32_cond_list_lock; +ptw32_mcs_lock_t ptw32_cond_list_lock = 0; #ifdef _UWIN /* diff --git a/implement.h b/implement.h index b210bc5..0b77d7d 100644 --- a/implement.h +++ b/implement.h @@ -112,19 +112,24 @@ typedef enum PThreadStateInitial = 0, /* Thread not running */ PThreadStateRunning, /* Thread alive & kicking */ PThreadStateSuspended, /* Thread alive but suspended */ - PThreadStateCancelPending, /* Thread alive but is */ - /* has cancelation pending. */ + PThreadStateCancelPending, /* Thread alive but */ + /* has cancelation pending. */ PThreadStateCanceling, /* Thread alive but is */ - /* in the process of terminating */ - /* due to a cancellation request */ - PThreadStateException, /* Thread alive but exiting */ - /* due to an exception */ - PThreadStateLast + /* in the process of terminating */ + /* due to a cancellation request */ + PThreadStateExiting, /* Thread alive but exiting */ + /* due to an exception */ + PThreadStateLast, /* All handlers have been run and now */ + /* final cleanup can be done. */ + PThreadStateReuse /* In reuse pool. */ } PThreadState; +typedef struct ptw32_mcs_node_t_ ptw32_mcs_local_node_t; +typedef struct ptw32_mcs_node_t_* ptw32_mcs_lock_t; +typedef struct ptw32_robust_node_t_ ptw32_robust_node_t; +typedef struct ptw32_thread_t_ ptw32_thread_t; -typedef struct ptw32_thread_t_ ptw32_thread_t; struct ptw32_thread_t_ { @@ -141,9 +146,9 @@ struct ptw32_thread_t_ void *parms; int ptErrno; int detachState; - pthread_mutex_t threadLock; /* Used for serialised access to public thread state */ + ptw32_mcs_lock_t threadLock; /* Used for serialised access to public thread state */ int sched_priority; /* As set, not as currently is */ - pthread_mutex_t cancelLock; /* Used for async-cancel safety */ + ptw32_mcs_lock_t stateLock; /* Used for async-cancel safety */ int cancelState; int cancelType; HANDLE cancelEvent; @@ -156,6 +161,10 @@ struct ptw32_thread_t_ int implicit:1; void *keys; void *nextAssoc; + ptw32_mcs_lock_t + robustMxListLock; /* robustMxList lock */ + ptw32_robust_node_t* + robustMxList; /* List of currenty held robust mutexes */ }; @@ -215,12 +224,39 @@ struct pthread_mutex_t_ pthread_t ownerThread; HANDLE event; /* Mutex release notification to waiting threads. */ + ptw32_robust_node_t* + robustNode; /* Extra state for robust mutexes */ +}; + +enum ptw32_robust_state_t_ +{ + PTW32_ROBUST_CONSISTENT, + PTW32_ROBUST_INCONSISTENT, + PTW32_ROBUST_NOTRECOVERABLE +}; + +typedef enum ptw32_robust_state_t_ ptw32_robust_state_t; + +/* + * Node used to manage per-thread lists of currently-held robust mutexes. + */ +struct ptw32_robust_node_t_ +{ + pthread_mutex_t mx; + ptw32_mcs_lock_t lock; /* Exclusive access to this robust mutex */ + ptw32_robust_state_t stateInconsistent; +#if 0 + int inList; +#endif + ptw32_robust_node_t* prev; + ptw32_robust_node_t* next; }; struct pthread_mutexattr_t_ { int pshared; int kind; + int robustness; }; /* @@ -267,9 +303,6 @@ struct ptw32_mcs_node_t_ successor */ }; -typedef struct ptw32_mcs_node_t_ ptw32_mcs_local_node_t; -typedef struct ptw32_mcs_node_t_ *ptw32_mcs_lock_t; - struct pthread_barrier_t_ { @@ -277,7 +310,7 @@ struct pthread_barrier_t_ unsigned int nInitialBarrierHeight; int pshared; sem_t semBarrierBreeched; - void * lock; /* MCS lock */ + ptw32_mcs_lock_t lock; ptw32_mcs_local_node_t proxynode; }; @@ -290,7 +323,7 @@ struct pthread_key_t_ { DWORD key; void (*destructor) (void *); - pthread_mutex_t keyLock; + ptw32_mcs_lock_t keyLock; void *threads; }; @@ -566,14 +599,16 @@ extern "C" int ptw32_mutex_check_need_init (pthread_mutex_t * mutex); int ptw32_rwlock_check_need_init (pthread_rwlock_t * rwlock); - PTW32_INTERLOCKED_LONG WINAPI - ptw32_InterlockedCompareExchange (PTW32_INTERLOCKED_LPLONG location, - PTW32_INTERLOCKED_LONG value, - PTW32_INTERLOCKED_LONG comparand); - - LONG WINAPI - ptw32_InterlockedExchange (LPLONG location, - LONG value); + int ptw32_robust_mutex_inherit(pthread_mutex_t * mutex, pthread_t self); +#if 1 + void ptw32_robust_mutex_add(pthread_mutex_t* mutex, pthread_t self); + void ptw32_robust_mutex_remove(pthread_mutex_t* mutex); + void ptw32_robust_mutex_quick_remove(pthread_mutex_t* mutex, ptw32_thread_t* otp); +#else + void ptw32_robust_mutex_add(pthread_mutex_t* mutex); + void ptw32_robust_mutex_remove(pthread_mutex_t* mutex, pthread_t self); + void ptw32_robust_mutex_quick_remove(pthread_mutex_t* mutex, ptw32_thread_t* tp); +#endif DWORD ptw32_RegisterCancelation (PAPCFUNC callback, diff --git a/mutex.c b/mutex.c index 0b03a45..8668324 100644 --- a/mutex.c +++ b/mutex.c @@ -53,7 +53,10 @@ #include "pthread_mutexattr_setpshared.c" #include "pthread_mutexattr_settype.c" #include "pthread_mutexattr_gettype.c" +#include "pthread_mutexattr_setrobust.c" +#include "pthread_mutexattr_getrobust.c" #include "pthread_mutex_lock.c" #include "pthread_mutex_timedlock.c" #include "pthread_mutex_unlock.c" #include "pthread_mutex_trylock.c" +#include "pthread_mutex_consistent.c" diff --git a/need_errno.h b/need_errno.h index 314e518..30c674d 100644 --- a/need_errno.h +++ b/need_errno.h @@ -129,6 +129,10 @@ _CRTIMP extern int errno; #define EILSEQ 42 +/* POSIX 2008 - robust mutexes */ +#define EOWNERDEAD 43 +#define ENOTRECOVERABLE 44 + /* * Support EDEADLOCK for compatibiity with older MS-C versions. */ diff --git a/pthread.h b/pthread.h index 294fe4c..0c0aeb8 100644 --- a/pthread.h +++ b/pthread.h @@ -273,7 +273,7 @@ enum { #endif #ifndef ETIMEDOUT -# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ +# define ETIMEDOUT 10060 /* Same as WSAETIMEDOUT */ #endif #ifndef ENOSYS @@ -288,6 +288,14 @@ enum { # endif #endif +/* POSIX 2008 - related to robust mutexes */ +#ifndef EOWNERDEAD +# define EOWNERDEAD 43 +#endif +#ifndef ENOTRECOVERABLE +# define ENOTRECOVERABLE 44 +#endif + #include /* @@ -424,22 +432,22 @@ extern "C" * POSIX Options */ #undef _POSIX_THREADS -#define _POSIX_THREADS 200112L +#define _POSIX_THREADS 200809L #undef _POSIX_READER_WRITER_LOCKS -#define _POSIX_READER_WRITER_LOCKS 200112L +#define _POSIX_READER_WRITER_LOCKS 200809L #undef _POSIX_SPIN_LOCKS -#define _POSIX_SPIN_LOCKS 200112L +#define _POSIX_SPIN_LOCKS 200809L #undef _POSIX_BARRIERS -#define _POSIX_BARRIERS 200112L +#define _POSIX_BARRIERS 200809L #undef _POSIX_THREAD_SAFE_FUNCTIONS -#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L +#define _POSIX_THREAD_SAFE_FUNCTIONS 200809L #undef _POSIX_THREAD_ATTR_STACKSIZE -#define _POSIX_THREAD_ATTR_STACKSIZE 200112L +#define _POSIX_THREAD_ATTR_STACKSIZE 200809L /* * The following options are not supported @@ -635,6 +643,12 @@ enum { PTHREAD_PROCESS_PRIVATE = 0, PTHREAD_PROCESS_SHARED = 1, +/* + * pthread_mutexattr_{get,set}robust + */ + PTHREAD_MUTEX_STALLED = 0, /* Default */ + PTHREAD_MUTEX_ROBUST = 1, + /* * pthread_barrier_wait */ @@ -992,6 +1006,13 @@ PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind); PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (const pthread_mutexattr_t * attr, int *kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setrobust( + pthread_mutexattr_t *attr, + int robust); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getrobust( + const pthread_mutexattr_t * attr, + int * robust); + /* * Barrier Attribute Functions */ @@ -1016,13 +1037,15 @@ PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex); PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex); -PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t *mutex, +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t * mutex, const struct timespec *abstime); PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex); PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex); +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_consistent (pthread_mutex_t * mutex); + /* * Spinlock Functions */ diff --git a/pthread_barrier_destroy.c b/pthread_barrier_destroy.c index baed212..55163cc 100644 --- a/pthread_barrier_destroy.c +++ b/pthread_barrier_destroy.c @@ -49,7 +49,7 @@ pthread_barrier_destroy (pthread_barrier_t * barrier) return EINVAL; } - if (0 != ptw32_mcs_lock_try_acquire((ptw32_mcs_lock_t *)&(*barrier)->lock, &node)) + if (0 != ptw32_mcs_lock_try_acquire(&(*barrier)->lock, &node)) { return EBUSY; } diff --git a/pthread_barrier_wait.c b/pthread_barrier_wait.c index b0b4481..d01b7d4 100644 --- a/pthread_barrier_wait.c +++ b/pthread_barrier_wait.c @@ -51,7 +51,7 @@ pthread_barrier_wait (pthread_barrier_t * barrier) return EINVAL; } - ptw32_mcs_lock_acquire((ptw32_mcs_lock_t *)&(*barrier)->lock, &node); + ptw32_mcs_lock_acquire(&(*barrier)->lock, &node); b = *barrier; if (--b->nCurrentBarrierHeight == 0) diff --git a/pthread_cancel.c b/pthread_cancel.c index 1d2ea67..ae60b72 100644 --- a/pthread_cancel.c +++ b/pthread_cancel.c @@ -99,6 +99,7 @@ pthread_cancel (pthread_t thread) int cancel_self; pthread_t self; ptw32_thread_t * tp; + ptw32_mcs_local_node_t stateLock; result = pthread_kill (thread, 0); @@ -125,7 +126,7 @@ pthread_cancel (pthread_t thread) /* * Lock for async-cancel safety. */ - (void) pthread_mutex_lock (&tp->cancelLock); + ptw32_mcs_lock_acquire (&tp->stateLock, &stateLock); if (tp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS && tp->cancelState == PTHREAD_CANCEL_ENABLE @@ -136,7 +137,7 @@ pthread_cancel (pthread_t thread) tp->state = PThreadStateCanceling; tp->cancelState = PTHREAD_CANCEL_DISABLE; - (void) pthread_mutex_unlock (&tp->cancelLock); + ptw32_mcs_lock_release (&stateLock); ptw32_throw (PTW32_EPS_CANCEL); /* Never reached */ @@ -158,7 +159,7 @@ pthread_cancel (pthread_t thread) * the threadH arg will be used. */ ptw32_register_cancelation ((PAPCFUNC)ptw32_cancel_callback, threadH, 0); - (void) pthread_mutex_unlock (&tp->cancelLock); + ptw32_mcs_lock_release (&stateLock); ResumeThread (threadH); } } @@ -181,7 +182,7 @@ pthread_cancel (pthread_t thread) result = ESRCH; } - (void) pthread_mutex_unlock (&tp->cancelLock); + ptw32_mcs_lock_release (&stateLock); } return (result); diff --git a/pthread_delay_np.c b/pthread_delay_np.c index f624fc8..e6c96d8 100644 --- a/pthread_delay_np.c +++ b/pthread_delay_np.c @@ -141,20 +141,21 @@ pthread_delay_np (struct timespec *interval) if (WAIT_OBJECT_0 == (status = WaitForSingleObject (sp->cancelEvent, wait_time))) { + ptw32_mcs_local_node_t stateLock; /* * Canceling! */ - (void) pthread_mutex_lock (&sp->cancelLock); + ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); if (sp->state < PThreadStateCanceling) { sp->state = PThreadStateCanceling; sp->cancelState = PTHREAD_CANCEL_DISABLE; - (void) pthread_mutex_unlock (&sp->cancelLock); + ptw32_mcs_lock_release (&stateLock); ptw32_throw (PTW32_EPS_CANCEL); } - (void) pthread_mutex_unlock (&sp->cancelLock); + ptw32_mcs_lock_release (&stateLock); return ESRCH; } else if (status != WAIT_TIMEOUT) diff --git a/pthread_detach.c b/pthread_detach.c index 19bc24d..84bfe1a 100644 --- a/pthread_detach.c +++ b/pthread_detach.c @@ -92,6 +92,7 @@ pthread_detach (pthread_t thread) } else { + ptw32_mcs_local_node_t stateLock; /* * Joinable ptw32_thread_t structs are not scavenged until * a join or detach is done. The thread may have exited already, @@ -99,26 +100,19 @@ pthread_detach (pthread_t thread) */ result = 0; - if (pthread_mutex_lock (&tp->cancelLock) == 0) - { - if (tp->state != PThreadStateLast) - { - tp->detachState = PTHREAD_CREATE_DETACHED; - } - else if (tp->detachState != PTHREAD_CREATE_DETACHED) - { - /* - * Thread is joinable and has exited or is exiting. - */ - destroyIt = PTW32_TRUE; - } - (void) pthread_mutex_unlock (&tp->cancelLock); - } - else - { - /* cancelLock shouldn't fail, but if it does ... */ - result = ESRCH; - } + ptw32_mcs_lock_acquire (&tp->stateLock, &stateLock); + if (tp->state != PThreadStateLast) + { + tp->detachState = PTHREAD_CREATE_DETACHED; + } + else if (tp->detachState != PTHREAD_CREATE_DETACHED) + { + /* + * Thread is joinable and has exited or is exiting. + */ + destroyIt = PTW32_TRUE; + } + ptw32_mcs_lock_release (&stateLock); } ptw32_mcs_lock_release(&node); diff --git a/pthread_key_create.c b/pthread_key_create.c index 41f4854..0851c0b 100644 --- a/pthread_key_create.c +++ b/pthread_key_create.c @@ -98,7 +98,7 @@ pthread_key_create (pthread_key_t * key, void (*destructor) (void *)) * * The mutex will only be created when it is first locked. */ - newkey->keyLock = PTHREAD_MUTEX_INITIALIZER; + newkey->keyLock = 0; newkey->destructor = destructor; } diff --git a/pthread_key_delete.c b/pthread_key_delete.c index 0737e9e..09d70c6 100644 --- a/pthread_key_delete.c +++ b/pthread_key_delete.c @@ -66,15 +66,15 @@ pthread_key_delete (pthread_key_t key) * ------------------------------------------------------ */ { + ptw32_mcs_local_node_t keyLock; int result = 0; if (key != NULL) { - if (key->threads != NULL && - key->destructor != NULL && - pthread_mutex_lock (&(key->keyLock)) == 0) + if (key->threads != NULL && key->destructor != NULL) { ThreadKeyAssoc *assoc; + ptw32_mcs_lock_acquire (&(key->keyLock), &keyLock); /* * Run through all Thread<-->Key associations * for this key. @@ -85,6 +85,7 @@ pthread_key_delete (pthread_key_t key) */ while ((assoc = (ThreadKeyAssoc *) key->threads) != NULL) { + ptw32_mcs_local_node_t threadLock; ptw32_thread_t * thread = assoc->thread; if (assoc == NULL) @@ -93,34 +94,25 @@ pthread_key_delete (pthread_key_t key) break; } - if (pthread_mutex_lock (&(thread->threadLock)) == 0) - { - /* - * Since we are starting at the head of the key's threads - * chain, this will also point key->threads at the next assoc. - * While we hold key->keyLock, no other thread can insert - * a new assoc via pthread_setspecific. - */ - ptw32_tkAssocDestroy (assoc); - (void) pthread_mutex_unlock (&(thread->threadLock)); - } - else - { - /* Thread or lock is no longer valid? */ - ptw32_tkAssocDestroy (assoc); - } + ptw32_mcs_lock_acquire (&(thread->threadLock), &threadLock); + /* + * Since we are starting at the head of the key's threads + * chain, this will also point key->threads at the next assoc. + * While we hold key->keyLock, no other thread can insert + * a new assoc via pthread_setspecific. + */ + ptw32_tkAssocDestroy (assoc); + ptw32_mcs_lock_release (&threadLock); + ptw32_mcs_lock_release (&keyLock); } - pthread_mutex_unlock (&(key->keyLock)); } TlsFree (key->key); if (key->destructor != NULL) { /* A thread could be holding the keyLock */ - while (EBUSY == pthread_mutex_destroy (&(key->keyLock))) - { - Sleep(0); /* Ugly */ - } + ptw32_mcs_lock_acquire (&(key->keyLock), &keyLock); + ptw32_mcs_lock_release (&keyLock); } #if defined( _DEBUG ) diff --git a/pthread_mutex_destroy.c b/pthread_mutex_destroy.c index c9460dc..7b8c9cd 100644 --- a/pthread_mutex_destroy.c +++ b/pthread_mutex_destroy.c @@ -61,7 +61,7 @@ pthread_mutex_destroy (pthread_mutex_t * mutex) * If trylock succeeded and the mutex is not recursively locked it * can be destroyed. */ - if (result == 0) + if (0 == result || ENOTRECOVERABLE == result) { if (mx->kind != PTHREAD_MUTEX_RECURSIVE || 1 == mx->recursive_count) { @@ -74,10 +74,14 @@ pthread_mutex_destroy (pthread_mutex_t * mutex) */ *mutex = NULL; - result = pthread_mutex_unlock (&mx); + result = (0 == result)?pthread_mutex_unlock(&mx):0; - if (result == 0) + if (0 == result) { + if (mx->robustNode != NULL) + { + free(mx->robustNode); + } if (!CloseHandle (mx->event)) { *mutex = mx; diff --git a/pthread_mutex_init.c b/pthread_mutex_init.c index cff8e50..93e7384 100644 --- a/pthread_mutex_init.c +++ b/pthread_mutex_init.c @@ -49,27 +49,28 @@ pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t * attr) return EINVAL; } - if (attr != NULL - && *attr != NULL && (*attr)->pshared == PTHREAD_PROCESS_SHARED) + if (attr != NULL && *attr != NULL) { - /* - * Creating mutex that can be shared between - * processes. - */ + if ((*attr)->pshared == PTHREAD_PROCESS_SHARED) + { + /* + * Creating mutex that can be shared between + * processes. + */ #if _POSIX_THREAD_PROCESS_SHARED >= 0 - /* - * Not implemented yet. - */ + /* + * Not implemented yet. + */ #error ERROR [__FILE__, line __LINE__]: Process shared mutexes are not supported yet. #else - return ENOSYS; + return ENOSYS; #endif /* _POSIX_THREAD_PROCESS_SHARED */ - + } } mx = (pthread_mutex_t) calloc (1, sizeof (*mx)); @@ -82,8 +83,34 @@ pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t * attr) { mx->lock_idx = 0; mx->recursive_count = 0; - mx->kind = (attr == NULL || *attr == NULL - ? PTHREAD_MUTEX_DEFAULT : (*attr)->kind); + mx->robustNode = NULL; + if (attr == NULL || *attr == NULL) + { + mx->kind = PTHREAD_MUTEX_DEFAULT; + } + else + { + mx->kind = (*attr)->kind; + if ((*attr)->robustness == PTHREAD_MUTEX_ROBUST) + { + /* + * Use the negative range to represent robust types. + * Replaces a memory fetch with a register negate and incr + * in pthread_mutex_lock etc. + * + * Map 0,1,..,n to -1,-2,..,(-n)-1 + */ + mx->kind = -mx->kind - 1; + + mx->robustNode = (ptw32_robust_node_t*) malloc(sizeof(ptw32_robust_node_t)); + mx->robustNode->stateInconsistent = PTW32_ROBUST_CONSISTENT; + mx->robustNode->lock = 0; + mx->robustNode->mx = mx; + mx->robustNode->next = NULL; + mx->robustNode->prev = NULL; + } + } + mx->ownerThread.p = NULL; mx->event = CreateEvent (NULL, PTW32_FALSE, /* manual reset = No */ diff --git a/pthread_mutex_lock.c b/pthread_mutex_lock.c index b819a7b..fe58a05 100644 --- a/pthread_mutex_lock.c +++ b/pthread_mutex_lock.c @@ -43,8 +43,9 @@ int pthread_mutex_lock (pthread_mutex_t * mutex) { - int result = 0; + int kind; pthread_mutex_t mx; + int result = 0; /* * Let the system deal with invalid pointers. @@ -69,71 +70,226 @@ pthread_mutex_lock (pthread_mutex_t * mutex) } mx = *mutex; + kind = mx->kind; - if (mx->kind == PTHREAD_MUTEX_NORMAL) + if (kind >= 0) { - if ((LONG) PTW32_INTERLOCKED_EXCHANGE( - (LPLONG) &mx->lock_idx, - (LONG) 1) != 0) - { - while ((LONG) PTW32_INTERLOCKED_EXCHANGE( - (LPLONG) &mx->lock_idx, - (LONG) -1) != 0) + /* Non-robust */ + if (PTHREAD_MUTEX_NORMAL == kind) + { + if ((LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) 1) != 0) { - if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) + while ((LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) -1) != 0) { - result = EINVAL; - break; + if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) + { + result = EINVAL; + break; + } } } - } - } - else - { - pthread_t self = pthread_self(); - - if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE( - (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, - (PTW32_INTERLOCKED_LONG) 1, - (PTW32_INTERLOCKED_LONG) 0) == 0) - { - mx->recursive_count = 1; - mx->ownerThread = self; - } + } else - { - if (pthread_equal (mx->ownerThread, self)) + { + pthread_t self = pthread_self(); + + if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE( + (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0) == 0) { - if (mx->kind == PTHREAD_MUTEX_RECURSIVE) - { - mx->recursive_count++; - } - else - { - result = EDEADLK; - } + mx->recursive_count = 1; + mx->ownerThread = self; } - else + else { - while ((LONG) PTW32_INTERLOCKED_EXCHANGE( - (LPLONG) &mx->lock_idx, - (LONG) -1) != 0) - { - if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) + if (pthread_equal (mx->ownerThread, self)) + { + if (kind == PTHREAD_MUTEX_RECURSIVE) { - result = EINVAL; - break; + mx->recursive_count++; + } + else + { + result = EDEADLK; + } + } + else + { + while ((LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) -1) != 0) + { + if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) + { + result = EINVAL; + break; + } } - } - if (0 == result) - { - mx->recursive_count = 1; - mx->ownerThread = self; - } + if (0 == result) + { + mx->recursive_count = 1; + mx->ownerThread = self; + } + } } - } + } + } + else + { + /* + * Robust types + * All types record the current owner thread. + * The mutex is added to a per thread list when ownership is acquired. + */ + ptw32_robust_state_t* statePtr = &mx->robustNode->stateInconsistent; + + if ((LONG)PTW32_ROBUST_NOTRECOVERABLE == PTW32_INTERLOCKED_EXCHANGE_ADD( + (LPLONG)statePtr, + 0L)) + { + result = ENOTRECOVERABLE; + } + else + { + pthread_t self = pthread_self(); + + kind = -kind - 1; /* Convert to non-robust range */ + + if (PTHREAD_MUTEX_NORMAL == kind) + { + if ((LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) 1) != 0) + { + while (0 == (result = ptw32_robust_mutex_inherit(mutex, self)) + && (LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) -1) != 0) + { +#if 0 + /* + * Only need to add the mutex to the list kept by the owner thread + * when a thread blocks on the mutex. + */ + ptw32_robust_mutex_add(mutex); +#endif + if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) + { + result = EINVAL; + break; + } + if ((LONG)PTW32_ROBUST_NOTRECOVERABLE == + PTW32_INTERLOCKED_EXCHANGE_ADD( + (LPLONG)statePtr, + 0L)) + { + /* Unblock the next thread */ + SetEvent(mx->event); + result = ENOTRECOVERABLE; + break; + } + } + } + if (0 == result || EOWNERDEAD == result) + { +#if 0 + mx->ownerThread = self; +#else + /* + * Add mutex to the per-thread robust mutex currently-held list. + * If the thread terminates, all mutexes in this list will be unlocked. + */ + ptw32_robust_mutex_add(mutex, self); +#endif + } + } + else + { + if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE( + (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0) == 0) + { + mx->recursive_count = 1; +#if 1 + /* + * Add mutex to the per-thread robust mutex currently-held list. + * If the thread terminates, all mutexes in this list will be unlocked. + */ + ptw32_robust_mutex_add(mutex, self); +#else + mx->ownerThread = self; +#endif + } + else + { + if (pthread_equal (mx->ownerThread, self)) + { + if (PTHREAD_MUTEX_RECURSIVE == kind) + { + mx->recursive_count++; + } + else + { + result = EDEADLK; + } + } + else + { + while (0 == (result = ptw32_robust_mutex_inherit(mutex, self)) + && (LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) -1) != 0) + { +#if 0 + /* + * Only need to add the mutex to the list kept by the owner thread + * when a thread blocks on the mutex. + */ + ptw32_robust_mutex_add(mutex); +#endif + if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) + { + result = EINVAL; + break; + } + if ((LONG)PTW32_ROBUST_NOTRECOVERABLE == + PTW32_INTERLOCKED_EXCHANGE_ADD( + (LPLONG)statePtr, + 0L)) + { + /* Unblock the next thread */ + SetEvent(mx->event); + result = ENOTRECOVERABLE; + break; + } + } + + if (0 == result || EOWNERDEAD == result) + { + mx->recursive_count = 1; +#if 1 + /* + * Add mutex to the per-thread robust mutex currently-held list. + * If the thread terminates, all mutexes in this list will be unlocked. + */ + ptw32_robust_mutex_add(mutex, self); +#else + mx->ownerThread = self; +#endif + } + } + } + } + } } return (result); } + diff --git a/pthread_mutex_timedlock.c b/pthread_mutex_timedlock.c index a238552..d81b9c3 100644 --- a/pthread_mutex_timedlock.c +++ b/pthread_mutex_timedlock.c @@ -109,8 +109,9 @@ int pthread_mutex_timedlock (pthread_mutex_t * mutex, const struct timespec *abstime) { - int result; pthread_mutex_t mx; + int kind; + int result = 0; /* * Let the system deal with invalid pointers. @@ -131,66 +132,211 @@ pthread_mutex_timedlock (pthread_mutex_t * mutex, } mx = *mutex; + kind = mx->kind; - if (mx->kind == PTHREAD_MUTEX_NORMAL) + if (kind >= 0) { - if ((LONG) PTW32_INTERLOCKED_EXCHANGE( - (LPLONG) &mx->lock_idx, - (LONG) 1) != 0) - { - while ((LONG) PTW32_INTERLOCKED_EXCHANGE( - (LPLONG) &mx->lock_idx, - (LONG) -1) != 0) - { - if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) - { - return result; - } - } - } - } - else - { - pthread_t self = pthread_self(); - - if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE( - (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, - (PTW32_INTERLOCKED_LONG) 1, - (PTW32_INTERLOCKED_LONG) 0) == 0) - { - mx->recursive_count = 1; - mx->ownerThread = self; - } - else - { - if (pthread_equal (mx->ownerThread, self)) - { - if (mx->kind == PTHREAD_MUTEX_RECURSIVE) - { - mx->recursive_count++; - } - else - { - return EDEADLK; - } - } - else + if (mx->kind == PTHREAD_MUTEX_NORMAL) + { + if ((LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) 1) != 0) { while ((LONG) PTW32_INTERLOCKED_EXCHANGE( (LPLONG) &mx->lock_idx, (LONG) -1) != 0) { - if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) + if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) { return result; } - } + } + } + } + else + { + pthread_t self = pthread_self(); + if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE( + (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0) == 0) + { mx->recursive_count = 1; mx->ownerThread = self; } - } + else + { + if (pthread_equal (mx->ownerThread, self)) + { + if (mx->kind == PTHREAD_MUTEX_RECURSIVE) + { + mx->recursive_count++; + } + else + { + return EDEADLK; + } + } + else + { + while ((LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) -1) != 0) + { + if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) + { + return result; + } + } + + mx->recursive_count = 1; + mx->ownerThread = self; + } + } + } } + else + { + /* + * Robust types + * All types record the current owner thread. + * The mutex is added to a per thread list when ownership is acquired. + */ + ptw32_robust_state_t* statePtr = &mx->robustNode->stateInconsistent; - return 0; + if ((LONG)PTW32_ROBUST_NOTRECOVERABLE == PTW32_INTERLOCKED_EXCHANGE_ADD( + (LPLONG)statePtr, + 0L)) + { + result = ENOTRECOVERABLE; + } + else + { + pthread_t self = pthread_self(); + + kind = -kind - 1; /* Convert to non-robust range */ + + if (PTHREAD_MUTEX_NORMAL == kind) + { + if ((LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) 1) != 0) + { + while (0 == (result = ptw32_robust_mutex_inherit(mutex, self)) + && (LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) -1) != 0) + { +#if 0 + ptw32_robust_mutex_add(mutex); +#endif + if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) + { + return result; + } + if ((LONG)PTW32_ROBUST_NOTRECOVERABLE == + PTW32_INTERLOCKED_EXCHANGE_ADD( + (LPLONG)statePtr, + 0L)) + { + /* Unblock the next thread */ + SetEvent(mx->event); + result = ENOTRECOVERABLE; + break; + } + } + + if (0 == result || EOWNERDEAD == result) + { +#if 1 + /* + * Add mutex to the per-thread robust mutex currently-held list. + * If the thread terminates, all mutexes in this list will be unlocked. + */ + ptw32_robust_mutex_add(mutex, self); +#else + mx->ownerThread = self; +#endif + } + } + } + else + { + pthread_t self = pthread_self(); + + if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE( + (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0) == 0) + { + mx->recursive_count = 1; +#if 1 + /* + * Add mutex to the per-thread robust mutex currently-held list. + * If the thread terminates, all mutexes in this list will be unlocked. + */ + ptw32_robust_mutex_add(mutex, self); +#else + mx->ownerThread = self; +#endif + } + else + { + if (pthread_equal (mx->ownerThread, self)) + { + if (PTHREAD_MUTEX_RECURSIVE == kind) + { + mx->recursive_count++; + } + else + { + return EDEADLK; + } + } + else + { + while (0 == (result = ptw32_robust_mutex_inherit(mutex, self)) + && (LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) -1) != 0) + { +#if 0 + ptw32_robust_mutex_add(mutex); +#endif + if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) + { + return result; + } + } + + if ((LONG)PTW32_ROBUST_NOTRECOVERABLE == + PTW32_INTERLOCKED_EXCHANGE_ADD( + (LPLONG)statePtr, + 0L)) + { + /* Unblock the next thread */ + SetEvent(mx->event); + result = ENOTRECOVERABLE; + } + else if (0 == result || EOWNERDEAD == result) + { + mx->recursive_count = 1; +#if 1 + /* + * Add mutex to the per-thread robust mutex currently-held list. + * If the thread terminates, all mutexes in this list will be unlocked. + */ + ptw32_robust_mutex_add(mutex, self); +#else + mx->ownerThread = self; +#endif + } + } + } + } + } + } + + return result; } diff --git a/pthread_mutex_trylock.c b/pthread_mutex_trylock.c index 50e8bc6..8f98661 100644 --- a/pthread_mutex_trylock.c +++ b/pthread_mutex_trylock.c @@ -41,8 +41,9 @@ int pthread_mutex_trylock (pthread_mutex_t * mutex) { - int result = 0; pthread_mutex_t mx; + int kind; + int result = 0; /* * Let the system deal with invalid pointers. @@ -63,29 +64,98 @@ pthread_mutex_trylock (pthread_mutex_t * mutex) } mx = *mutex; + kind = mx->kind; - if (0 == (LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE ( - (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, - (PTW32_INTERLOCKED_LONG) 1, - (PTW32_INTERLOCKED_LONG) 0)) + if (kind >= 0) { - if (mx->kind != PTHREAD_MUTEX_NORMAL) - { - mx->recursive_count = 1; - mx->ownerThread = pthread_self (); - } + /* Non-robust */ + if (0 == (LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE ( + (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0)) + { + if (kind != PTHREAD_MUTEX_NORMAL) + { + mx->recursive_count = 1; + mx->ownerThread = pthread_self (); + } + } + else + { + if (kind == PTHREAD_MUTEX_RECURSIVE && + pthread_equal (mx->ownerThread, pthread_self ())) + { + mx->recursive_count++; + } + else + { + result = EBUSY; + } + } } else { - if (mx->kind == PTHREAD_MUTEX_RECURSIVE && - pthread_equal (mx->ownerThread, pthread_self ())) - { - mx->recursive_count++; - } + /* + * Robust types + * All types record the current owner thread. + * The mutex is added to a per thread list when ownership is acquired. + */ + pthread_t self; + ptw32_robust_state_t* statePtr = &mx->robustNode->stateInconsistent; + + if ((LONG)PTW32_ROBUST_NOTRECOVERABLE == + PTW32_INTERLOCKED_EXCHANGE_ADD( + (LPLONG)statePtr, + 0L)) + { + return ENOTRECOVERABLE; + } + + self = pthread_self(); + kind = -kind - 1; /* Convert to non-robust range */ + + if (0 == (LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE ( + (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0)) + { + if (kind != PTHREAD_MUTEX_NORMAL) + { + mx->recursive_count = 1; + } +#if 1 + ptw32_robust_mutex_add(mutex, self); +#else + mx->ownerThread = self; +#endif + } else - { - result = EBUSY; - } + { + if (PTHREAD_MUTEX_RECURSIVE == kind && + pthread_equal (mx->ownerThread, pthread_self ())) + { + mx->recursive_count++; + } + else + { + if (EOWNERDEAD == (result = ptw32_robust_mutex_inherit(mutex, self))) + { + mx->recursive_count = 1; +#if 1 + ptw32_robust_mutex_add(mutex, self); +#else + mx->ownerThread = self; +#endif + } + else + { + if (0 == result) + { + result = EBUSY; + } + } + } + } } return (result); diff --git a/pthread_mutex_unlock.c b/pthread_mutex_unlock.c index 9ebe4e3..7a3f009 100644 --- a/pthread_mutex_unlock.c +++ b/pthread_mutex_unlock.c @@ -42,6 +42,7 @@ int pthread_mutex_unlock (pthread_mutex_t * mutex) { int result = 0; + int kind; pthread_mutex_t mx; /* @@ -57,60 +58,129 @@ pthread_mutex_unlock (pthread_mutex_t * mutex) */ if (mx < PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) { - if (mx->kind == PTHREAD_MUTEX_NORMAL) - { - LONG idx; + kind = mx->kind; - idx = (LONG) PTW32_INTERLOCKED_EXCHANGE ((LPLONG) &mx->lock_idx, - (LONG) 0); - if (idx != 0) + if (kind >= 0) + { + if (kind == PTHREAD_MUTEX_NORMAL) { - if (idx < 0) - { - /* - * Someone may be waiting on that mutex. - */ - if (SetEvent (mx->event) == 0) - { - result = EINVAL; - } - } - } - else - { - /* - * Was not locked (so can't be owned by us). - */ - result = EPERM; - } - } - else - { - if (pthread_equal (mx->ownerThread, pthread_self ())) - { - if (mx->kind != PTHREAD_MUTEX_RECURSIVE - || 0 == --mx->recursive_count) - { - mx->ownerThread.p = NULL; + LONG idx; - if ((LONG) PTW32_INTERLOCKED_EXCHANGE ((LPLONG) &mx->lock_idx, - (LONG) 0) < 0) + idx = (LONG) PTW32_INTERLOCKED_EXCHANGE ((LPLONG) &mx->lock_idx, + (LONG) 0); + if (idx != 0) + { + if (idx < 0) { - /* Someone may be waiting on that mutex */ + /* + * Someone may be waiting on that mutex. + */ if (SetEvent (mx->event) == 0) - { - result = EINVAL; - } + { + result = EINVAL; + } } - } + } } - else + else { - result = EPERM; + if (pthread_equal (mx->ownerThread, pthread_self())) + { + if (kind != PTHREAD_MUTEX_RECURSIVE + || 0 == --mx->recursive_count) + { + mx->ownerThread.p = NULL; + + if ((LONG) PTW32_INTERLOCKED_EXCHANGE ((LPLONG) &mx->lock_idx, + (LONG) 0) < 0) + { + /* Someone may be waiting on that mutex */ + if (SetEvent (mx->event) == 0) + { + result = EINVAL; + } + } + } + } + else + { + result = EPERM; + } } - } + } + else + { + /* Robust types */ + pthread_t self = pthread_self(); + kind = -kind - 1; /* Convert to non-robust range */ + + /* + * The thread must own the lock regardless of type if the mutex + * is robust. + */ + if (pthread_equal (mx->ownerThread, self)) + { + PTW32_INTERLOCKED_COMPARE_EXCHANGE((LPLONG) &mx->robustNode->stateInconsistent, + (LONG)PTW32_ROBUST_NOTRECOVERABLE, + (LONG)PTW32_ROBUST_INCONSISTENT); + if (PTHREAD_MUTEX_NORMAL == kind) + { +#if 1 + ptw32_robust_mutex_remove(mutex); +#else + mx->ownerThread.p = NULL; +#endif + + if ((LONG) PTW32_INTERLOCKED_EXCHANGE((LPLONG) &mx->lock_idx, + (LONG) 0) < 0) + { +#if 0 + ptw32_robust_mutex_remove(mutex, self); +#endif + /* + * Someone may be waiting on that mutex. + */ + if (SetEvent (mx->event) == 0) + { + result = EINVAL; + } + } + } + else + { + if (kind != PTHREAD_MUTEX_RECURSIVE + || 0 == --mx->recursive_count) + { +#if 1 + ptw32_robust_mutex_remove(mutex); +#else + mx->ownerThread.p = NULL; +#endif + + if ((LONG) PTW32_INTERLOCKED_EXCHANGE((LPLONG) &mx->lock_idx, + (LONG) 0) < 0) + { +#if 0 + ptw32_robust_mutex_remove(mutex, self); +#endif + /* + * Someone may be waiting on that mutex. + */ + if (SetEvent (mx->event) == 0) + { + result = EINVAL; + } + } + } + } + } + else + { + result = EPERM; + } + } } - else + else if (mx != PTHREAD_MUTEX_INITIALIZER) { result = EINVAL; } diff --git a/pthread_setcancelstate.c b/pthread_setcancelstate.c index 002cfe5..bbcd624 100644 --- a/pthread_setcancelstate.c +++ b/pthread_setcancelstate.c @@ -79,6 +79,7 @@ pthread_setcancelstate (int state, int *oldstate) * ------------------------------------------------------ */ { + ptw32_mcs_local_node_t stateLock; int result = 0; pthread_t self = pthread_self (); ptw32_thread_t * sp = (ptw32_thread_t *) self.p; @@ -92,7 +93,7 @@ pthread_setcancelstate (int state, int *oldstate) /* * Lock for async-cancel safety. */ - (void) pthread_mutex_lock (&sp->cancelLock); + ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); if (oldstate != NULL) { @@ -111,13 +112,13 @@ pthread_setcancelstate (int state, int *oldstate) sp->state = PThreadStateCanceling; sp->cancelState = PTHREAD_CANCEL_DISABLE; ResetEvent (sp->cancelEvent); - (void) pthread_mutex_unlock (&sp->cancelLock); + ptw32_mcs_lock_release (&stateLock); ptw32_throw (PTW32_EPS_CANCEL); /* Never reached */ } - (void) pthread_mutex_unlock (&sp->cancelLock); + ptw32_mcs_lock_release (&stateLock); return (result); diff --git a/pthread_setcanceltype.c b/pthread_setcanceltype.c index 3fb3f0e..72b0af5 100644 --- a/pthread_setcanceltype.c +++ b/pthread_setcanceltype.c @@ -79,6 +79,7 @@ pthread_setcanceltype (int type, int *oldtype) * ------------------------------------------------------ */ { + ptw32_mcs_local_node_t stateLock; int result = 0; pthread_t self = pthread_self (); ptw32_thread_t * sp = (ptw32_thread_t *) self.p; @@ -93,7 +94,7 @@ pthread_setcanceltype (int type, int *oldtype) /* * Lock for async-cancel safety. */ - (void) pthread_mutex_lock (&sp->cancelLock); + ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); if (oldtype != NULL) { @@ -112,13 +113,13 @@ pthread_setcanceltype (int type, int *oldtype) sp->state = PThreadStateCanceling; sp->cancelState = PTHREAD_CANCEL_DISABLE; ResetEvent (sp->cancelEvent); - (void) pthread_mutex_unlock (&sp->cancelLock); + ptw32_mcs_lock_release (&stateLock); ptw32_throw (PTW32_EPS_CANCEL); /* Never reached */ } - (void) pthread_mutex_unlock (&sp->cancelLock); + ptw32_mcs_lock_release (&stateLock); return (result); diff --git a/pthread_setschedparam.c b/pthread_setschedparam.c index a122eac..b762753 100644 --- a/pthread_setschedparam.c +++ b/pthread_setschedparam.c @@ -71,7 +71,8 @@ int ptw32_setthreadpriority (pthread_t thread, int policy, int priority) { int prio; - int result; + ptw32_mcs_local_node_t threadLock; + int result = 0; ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; prio = priority; @@ -100,26 +101,23 @@ ptw32_setthreadpriority (pthread_t thread, int policy, int priority) #endif - result = pthread_mutex_lock (&tp->threadLock); + ptw32_mcs_lock_acquire (&tp->threadLock, &threadLock); - if (0 == result) + /* If this fails, the current priority is unchanged. */ + if (0 == SetThreadPriority (tp->threadH, prio)) + { + result = EINVAL; + } + else { - /* If this fails, the current priority is unchanged. */ - if (0 == SetThreadPriority (tp->threadH, prio)) - { - result = EINVAL; - } - else - { - /* - * Must record the thread's sched_priority as given, - * not as finally adjusted. - */ - tp->sched_priority = priority; - } - - (void) pthread_mutex_unlock (&tp->threadLock); + /* + * Must record the thread's sched_priority as given, + * not as finally adjusted. + */ + tp->sched_priority = priority; } + ptw32_mcs_lock_release (&threadLock); + return result; } diff --git a/pthread_setspecific.c b/pthread_setspecific.c index b16270e..0f29e70 100644 --- a/pthread_setspecific.c +++ b/pthread_setspecific.c @@ -109,6 +109,9 @@ pthread_setspecific (pthread_key_t key, const void *value) { if (self.p != NULL && key->destructor != NULL && value != NULL) { + ptw32_mcs_local_node_t keyLock; + ptw32_mcs_local_node_t threadLock; + ptw32_thread_t * sp = (ptw32_thread_t *) self.p; /* * Only require associations if we have to * call user destroy routine. @@ -120,39 +123,35 @@ pthread_setspecific (pthread_key_t key, const void *value) */ ThreadKeyAssoc *assoc; - if (pthread_mutex_lock(&(key->keyLock)) == 0) - { - ptw32_thread_t * sp = (ptw32_thread_t *) self.p; - - (void) pthread_mutex_lock(&(sp->threadLock)); + ptw32_mcs_lock_acquire(&(key->keyLock), &keyLock); + ptw32_mcs_lock_acquire(&(sp->threadLock), &threadLock); - assoc = (ThreadKeyAssoc *) sp->keys; - /* - * Locate existing association - */ - while (assoc != NULL) - { - if (assoc->key == key) - { - /* - * Association already exists - */ - break; - } - assoc = assoc->nextKey; - } - - /* - * create an association if not found - */ - if (assoc == NULL) + assoc = (ThreadKeyAssoc *) sp->keys; + /* + * Locate existing association + */ + while (assoc != NULL) + { + if (assoc->key == key) { - result = ptw32_tkAssocCreate (sp, key); + /* + * Association already exists + */ + break; } + assoc = assoc->nextKey; + } - (void) pthread_mutex_unlock(&(sp->threadLock)); + /* + * create an association if not found + */ + if (assoc == NULL) + { + result = ptw32_tkAssocCreate (sp, key); } - (void) pthread_mutex_unlock(&(key->keyLock)); + + ptw32_mcs_lock_release(&threadLock); + ptw32_mcs_lock_release(&keyLock); } if (result == 0) diff --git a/pthread_testcancel.c b/pthread_testcancel.c index 9686d9e..6658650 100644 --- a/pthread_testcancel.c +++ b/pthread_testcancel.c @@ -68,6 +68,7 @@ pthread_testcancel (void) * ------------------------------------------------------ */ { + ptw32_mcs_local_node_t stateLock; pthread_t self = pthread_self (); ptw32_thread_t * sp = (ptw32_thread_t *) self.p; @@ -86,17 +87,17 @@ pthread_testcancel (void) return; } - (void) pthread_mutex_lock (&sp->cancelLock); + ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); if (sp->cancelState != PTHREAD_CANCEL_DISABLE) { ResetEvent(sp->cancelEvent); sp->state = PThreadStateCanceling; sp->cancelState = PTHREAD_CANCEL_DISABLE; - (void) pthread_mutex_unlock (&sp->cancelLock); + ptw32_mcs_lock_release (&stateLock); ptw32_throw (PTW32_EPS_CANCEL); /* Never returns here */ } - (void) pthread_mutex_unlock (&sp->cancelLock); + ptw32_mcs_lock_release (&stateLock); } /* pthread_testcancel */ diff --git a/pthread_win32_attach_detach_np.c b/pthread_win32_attach_detach_np.c index 8116dd7..98935fb 100644 --- a/pthread_win32_attach_detach_np.c +++ b/pthread_win32_attach_detach_np.c @@ -190,15 +190,39 @@ pthread_win32_thread_detach_np () if (sp != NULL) // otherwise Win32 thread with no implicit POSIX handle. { + ptw32_mcs_local_node_t stateLock; + ptw32_mcs_local_node_t listLock; ptw32_callUserDestroyRoutines (sp->ptHandle); - (void) pthread_mutex_lock (&sp->cancelLock); + ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); sp->state = PThreadStateLast; /* * If the thread is joinable at this point then it MUST be joined * or detached explicitly by the application. */ - (void) pthread_mutex_unlock (&sp->cancelLock); + ptw32_mcs_lock_release (&stateLock); + + /* + * Robust Mutexes + */ + ptw32_mcs_lock_acquire(&sp->robustMxListLock, &listLock); + while (sp->robustMxList != NULL) + { + pthread_mutex_t mx = sp->robustMxList->mx; +#if 1 + ptw32_robust_mutex_quick_remove(&mx, sp); +#else + ptw32_robust_mutex_quick_remove(&mx, sp); +#endif + /* + * If there are no waiters then the next thread to block will + * sleep, wakeup immediately and then go back to sleep. + * See pthread_mutex_lock.c. + */ + SetEvent(mx->event); + } + ptw32_mcs_lock_release(&listLock); + if (sp->detachState == PTHREAD_CREATE_DETACHED) { diff --git a/ptw32_MCS_lock.c b/ptw32_MCS_lock.c index ee89880..02cdc5e 100644 --- a/ptw32_MCS_lock.c +++ b/ptw32_MCS_lock.c @@ -72,18 +72,18 @@ * ptw32_mcs_local_node_t node; * * ptw32_mcs_acquire (&lock1, &node); - * ptw32_mcs_release (&node); + * ptw32_mcs_lock_release (&node); * - * ptw32_mcs_acquire (&lock2, &node); - * ptw32_mcs_release (&node); + * ptw32_mcs_lock_acquire (&lock2, &node); + * ptw32_mcs_lock_release (&node); * { * ptw32_mcs_local_node_t nodex; * - * ptw32_mcs_acquire (&lock1, &node); - * ptw32_mcs_acquire (&lock2, &nodex); + * ptw32_mcs_lock_acquire (&lock1, &node); + * ptw32_mcs_lock_acquire (&lock2, &nodex); * - * ptw32_mcs_release (&nodex); - * ptw32_mcs_release (&node); + * ptw32_mcs_lock_release (&nodex); + * ptw32_mcs_lock_release (&node); * } * return (void *)0; * } diff --git a/ptw32_callUserDestroyRoutines.c b/ptw32_callUserDestroyRoutines.c index a583f18..8873f87 100644 --- a/ptw32_callUserDestroyRoutines.c +++ b/ptw32_callUserDestroyRoutines.c @@ -68,6 +68,8 @@ ptw32_callUserDestroyRoutines (pthread_t thread) if (thread.p != NULL) { + ptw32_mcs_local_node_t threadLock; + ptw32_mcs_local_node_t keyLock; int assocsRemaining; int iterations = 0; ptw32_thread_t * sp = (ptw32_thread_t *) thread.p; @@ -83,7 +85,7 @@ ptw32_callUserDestroyRoutines (pthread_t thread) assocsRemaining = 0; iterations++; - (void) pthread_mutex_lock(&(sp->threadLock)); + ptw32_mcs_lock_acquire(&(sp->threadLock), &threadLock); /* * The pointer to the next assoc is stored in the thread struct so that * the assoc destructor in pthread_key_delete can adjust it @@ -93,7 +95,7 @@ ptw32_callUserDestroyRoutines (pthread_t thread) * before us. */ sp->nextAssoc = sp->keys; - (void) pthread_mutex_unlock(&(sp->threadLock)); + ptw32_mcs_lock_release(&threadLock); for (;;) { @@ -106,12 +108,12 @@ ptw32_callUserDestroyRoutines (pthread_t thread) * both assoc guards, but in the reverse order to our convention, * so we must be careful to avoid deadlock. */ - (void) pthread_mutex_lock(&(sp->threadLock)); + ptw32_mcs_lock_acquire(&(sp->threadLock), &threadLock); if ((assoc = (ThreadKeyAssoc *)sp->nextAssoc) == NULL) { /* Finished */ - pthread_mutex_unlock(&(sp->threadLock)); + ptw32_mcs_lock_release(&threadLock); break; } else @@ -126,10 +128,10 @@ ptw32_callUserDestroyRoutines (pthread_t thread) * If we fail, we need to relinquish the first lock and the * processor and then try to acquire them all again. */ - if (pthread_mutex_trylock(&(assoc->key->keyLock)) == EBUSY) + if (ptw32_mcs_lock_try_acquire(&(assoc->key->keyLock), &keyLock) == EBUSY) { - pthread_mutex_unlock(&(sp->threadLock)); - Sleep(1); // Ugly but necessary to avoid priority effects. + ptw32_mcs_lock_release(&threadLock); + Sleep(0); /* * Go around again. * If pthread_key_delete has removed this assoc in the meantime, @@ -165,8 +167,8 @@ ptw32_callUserDestroyRoutines (pthread_t thread) * pthread_setspecific can also be run from destructors and * also needs to be able to access the assocs. */ - (void) pthread_mutex_unlock(&(sp->threadLock)); - (void) pthread_mutex_unlock(&(k->keyLock)); + ptw32_mcs_lock_release(&threadLock); + ptw32_mcs_lock_release(&keyLock); assocsRemaining++; @@ -210,8 +212,8 @@ ptw32_callUserDestroyRoutines (pthread_t thread) * and reclaim it's memory resources. */ ptw32_tkAssocDestroy (assoc); - (void) pthread_mutex_unlock(&(sp->threadLock)); - (void) pthread_mutex_unlock(&(k->keyLock)); + ptw32_mcs_lock_release(&threadLock); + ptw32_mcs_lock_release(&keyLock); } } } diff --git a/ptw32_new.c b/ptw32_new.c index 2812567..881c6ac 100644 --- a/ptw32_new.c +++ b/ptw32_new.c @@ -74,8 +74,10 @@ ptw32_new (void) tp->detachState = PTHREAD_CREATE_JOINABLE; tp->cancelState = PTHREAD_CANCEL_ENABLE; tp->cancelType = PTHREAD_CANCEL_DEFERRED; - tp->cancelLock = PTHREAD_MUTEX_INITIALIZER; - tp->threadLock = PTHREAD_MUTEX_INITIALIZER; + tp->stateLock = 0; + tp->threadLock = 0; + tp->robustMxListLock = 0; + tp->robustMxList = NULL; tp->cancelEvent = CreateEvent (0, (int) PTW32_TRUE, /* manualReset */ (int) PTW32_FALSE, /* setSignaled */ NULL); diff --git a/ptw32_reuse.c b/ptw32_reuse.c index 79e4dee..31ebdc4 100644 --- a/ptw32_reuse.c +++ b/ptw32_reuse.c @@ -132,6 +132,8 @@ ptw32_threadReusePush (pthread_t thread) tp->ptHandle.x++; #endif + tp->state = PThreadStateReuse; + tp->prevReuse = PTW32_THREAD_REUSE_EMPTY; if (PTW32_THREAD_REUSE_EMPTY != ptw32_threadReuseBottom) diff --git a/ptw32_threadDestroy.c b/ptw32_threadDestroy.c index 9e3b688..41499b1 100644 --- a/ptw32_threadDestroy.c +++ b/ptw32_threadDestroy.c @@ -64,9 +64,6 @@ ptw32_threadDestroy (pthread_t thread) CloseHandle (threadCopy.cancelEvent); } - (void) pthread_mutex_destroy(&threadCopy.cancelLock); - (void) pthread_mutex_destroy(&threadCopy.threadLock); - #if ! (defined(__MINGW64__) || defined(__MINGW32__)) || defined (__MSVCRT__) || defined (__DMC__) /* * See documentation for endthread vs endthreadex. diff --git a/ptw32_threadStart.c b/ptw32_threadStart.c index c485d16..5c354d4 100644 --- a/ptw32_threadStart.c +++ b/ptw32_threadStart.c @@ -69,7 +69,6 @@ ExceptionFilter (EXCEPTION_POINTERS * ep, DWORD * ei) */ pthread_t self = pthread_self (); - (void) pthread_mutex_destroy (&((ptw32_thread_t *)self.p)->cancelLock); ptw32_callUserDestroyRoutines (self); return EXCEPTION_CONTINUE_SEARCH; @@ -139,6 +138,7 @@ ptw32_threadStart (void *vthreadParms) int setjmp_rc; #endif + ptw32_mcs_local_node_t stateLock; void * status = (void *) 0; self = threadParms->tid; @@ -155,19 +155,19 @@ ptw32_threadStart (void *vthreadParms) */ sp->thread = GetCurrentThreadId (); /* - * Here we're using cancelLock as a general-purpose lock + * Here we're using stateLock as a general-purpose lock * to make the new thread wait until the creating thread * has the new handle. */ - if (pthread_mutex_lock (&sp->cancelLock) == 0) - { - (void) pthread_mutex_unlock (&sp->cancelLock); - } -#endif - + ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); pthread_setspecific (ptw32_selfThreadKey, sp); +#else + pthread_setspecific (ptw32_selfThreadKey, sp); + ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); +#endif sp->state = PThreadStateRunning; + ptw32_mcs_lock_release (&stateLock); #ifdef __CLEANUP_SEH @@ -177,6 +177,7 @@ ptw32_threadStart (void *vthreadParms) * Run the caller's routine; */ status = sp->exitStatus = (*start) (arg); + sp->state = PThreadStateExiting; #ifdef _UWIN if (--pthread_count <= 0) @@ -217,6 +218,7 @@ ptw32_threadStart (void *vthreadParms) * Run the caller's routine; */ status = sp->exitStatus = (*start) (arg); + sp->state = PThreadStateExiting; } else { @@ -250,6 +252,7 @@ ptw32_threadStart (void *vthreadParms) try { status = sp->exitStatus = (*start) (arg); + sp->state = PThreadStateExiting; } catch (ptw32_exception &) { diff --git a/ptw32_throw.c b/ptw32_throw.c index cd8f874..19f9e11 100644 --- a/ptw32_throw.c +++ b/ptw32_throw.c @@ -70,6 +70,8 @@ ptw32_throw (DWORD exception) DWORD exceptionInformation[3]; #endif + sp->state = PThreadStateExiting; + if (exception != PTW32_EPS_CANCEL && exception != PTW32_EPS_EXIT) { /* Should never enter here */ diff --git a/ptw32_tkAssocCreate.c b/ptw32_tkAssocCreate.c index 5ba24bb..50d6c50 100644 --- a/ptw32_tkAssocCreate.c +++ b/ptw32_tkAssocCreate.c @@ -78,7 +78,7 @@ ptw32_tkAssocCreate (ptw32_thread_t * sp, pthread_key_t key) * Have to create an association and add it * to both the key and the thread. * - * Both key->keyLock and thread->threadLock are locked on + * Both key->keyLock and thread->threadLock are locked before * entry to this routine. */ assoc = (ThreadKeyAssoc *) calloc (1, sizeof (*assoc)); diff --git a/ptw32_tkAssocDestroy.c b/ptw32_tkAssocDestroy.c index a7842ea..fedebf5 100644 --- a/ptw32_tkAssocDestroy.c +++ b/ptw32_tkAssocDestroy.c @@ -57,7 +57,7 @@ ptw32_tkAssocDestroy (ThreadKeyAssoc * assoc) { /* - * Both key->keyLock and thread->threadLock are locked on + * Both key->keyLock and thread->threadLock are locked before * entry to this routine. */ if (assoc != NULL) diff --git a/tests/Bmakefile b/tests/Bmakefile index 27228ad..263d127 100644 --- a/tests/Bmakefile +++ b/tests/Bmakefile @@ -92,6 +92,7 @@ PASSES= loadfree.pass \ mutex6s.pass mutex6es.pass mutex6rs.pass \ mutex7.pass mutex7n.pass mutex7e.pass mutex7r.pass \ mutex8.pass mutex8n.pass mutex8e.pass mutex8r.pass \ + robust1.pass robust2.pass robust3.pass robust4.pass robust5.pass \ count1.pass \ once1.pass once2.pass once3.pass once4.pass \ self2.pass \ @@ -310,6 +311,11 @@ mutex8.pass: mutex7.pass mutex8n.pass: mutex7n.pass mutex8e.pass: mutex7e.pass mutex8r.pass: mutex7r.pass +robust1.pass: mutex8r.pass +robust2.pass: mutex8r.pass +robust3.pass: robust2.pass +robust4.pass: robust3.pass +robust5.pass: robust4.pass once1.pass: create1.pass once2.pass: once1.pass once3.pass: once2.pass diff --git a/tests/ChangeLog b/tests/ChangeLog index 1ca1711..8d7604f 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,18 @@ +2011-03-24 Ross Johnson + + * mutex*.c: Include tests for robust mutexes wherever + appropriate. + * benchtest*.c: Include comparisons for robust mutexes. + * robust1.c: New test for robust mutex handling. + * robust2.c: Likewise. + * robust3.c: Likewise. + * robust4.c: Likewise. + * robust5.c: Likewise. + * GNUmakefile: Include new tests. + * Makefile: Likewise. + * Bmakefile: Likewise (not tested). + * Wmakefile: Likewise (not tested). + 2011-03-06 Ross Johnson * several (MINGW64): Cast and call fixups for 64 bit compatibility; diff --git a/tests/GNUmakefile b/tests/GNUmakefile index d90fe79..98342cc 100644 --- a/tests/GNUmakefile +++ b/tests/GNUmakefile @@ -57,8 +57,10 @@ RANLIB = $(CROSS)ranlib # XXCFLAGS = XXLIBS = -lws2_32 -lgomp +OPT = -O3 +DOPT = -g -O0 #CFLAGS = -O3 -UNDEBUG -Wall $(XXCFLAGS) -CFLAGS = -O3 -UNDEBUG -Wall $(XXCFLAGS) +CFLAGS = ${OPT} -UNDEBUG -Wall $(XXCFLAGS) BUILD_DIR = .. INCLUDES = -I. @@ -97,6 +99,7 @@ TESTS = \ mutex4 mutex6 mutex6n mutex6e mutex6r \ mutex6s mutex6es mutex6rs \ mutex7 mutex7n mutex7e mutex7r mutex8 mutex8n mutex8e mutex8r \ + robust1 robust2 robust3 robust4 robust5 \ count1 \ once1 once2 once3 once4 self2 \ cancel1 cancel2 \ @@ -135,6 +138,7 @@ STATICTESTS = \ mutex4 mutex6 mutex6n mutex6e mutex6r \ mutex6s mutex6es mutex6rs \ mutex7 mutex7n mutex7e mutex7r mutex8 mutex8n mutex8e mutex8r \ + robust1 robust2 robust3 robust4 robust5 \ count1 \ once1 once2 once3 once4 self2 \ cancel1 cancel2 \ @@ -172,6 +176,7 @@ help: @ $(ECHO) "make clean GC-stress (to stresstest using GNU C dll with C cleanup code)" @ $(ECHO) "make clean GCE-stress (to stresstest using GNU C dll with C++ exception handling)" @ $(ECHO) "make clean GC-static (to test using GC static lib with C (no EH) applications)" + @ $(ECHO) "make clean GC-debug (to test using GC dll with C (no EH) applications)" all: @ $(MAKE) clean GC @@ -197,7 +202,10 @@ GCE-bench: $(MAKE) TEST=GCE CC=$(CXX) XXCFLAGS="-mthreads -D__CLEANUP_CXX" XXLIBS="benchlib." all-bench GC-debug: - $(MAKE) TEST=GC CC=$(CC) XXCFLAGS="-fopenmp -D__CLEANUP_C" DLL_VER="$(DLL_VER)d" all-pass + $(MAKE) TEST=GC CC=$(CC) XXCFLAGS="-fopenmp -D__CLEANUP_C" OPT="${DOPT}" DLL_VER="$(DLL_VER)d" all-pass + +GC-bench-debug: + $(MAKE) TEST=GC CC=$(CC) XXCFLAGS="-D__CLEANUP_C" XXLIBS="benchlib.o" OPT="${OPT}" DLL_VER="$(DLL_VER)d" all-bench GC-static: $(MAKE) TEST=GC CC=$(CC) XXCFLAGS="-D__CLEANUP_C -DPTW32_STATIC_LIB" XXLIBS="-lws2_32" DLL="" all-static @@ -321,6 +329,11 @@ mutex8.pass: mutex7.pass mutex8n.pass: mutex7n.pass mutex8e.pass: mutex7e.pass mutex8r.pass: mutex7r.pass +robust1.pass: mutex8r.pass +robust2.pass: mutex8r.pass +robust3.pass: robust2.pass +robust4.pass: robust3.pass +robust5.pass: robust4.pass once1.pass: create1.pass once2.pass: once1.pass once3.pass: once2.pass diff --git a/tests/Makefile b/tests/Makefile index 606f1d4..5439ee1 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -96,6 +96,7 @@ PASSES= sizes.pass loadfree.pass \ mutex6s.pass mutex6es.pass mutex6rs.pass \ mutex7.pass mutex7n.pass mutex7e.pass mutex7r.pass \ mutex8.pass mutex8n.pass mutex8e.pass mutex8r.pass \ + robust1.pass robust2.pass robust3.pass robust4.pass robust5.pass \ count1.pass \ once1.pass once2.pass once3.pass once4.pass \ self2.pass \ @@ -141,6 +142,7 @@ STATICRESULTS = \ mutex6s.pass mutex6es.pass mutex6rs.pass \ mutex7.pass mutex7n.pass mutex7e.pass mutex7r.pass \ mutex8.pass mutex8n.pass mutex8e.pass mutex8r.pass \ + robust1.pass robust2.pass robust3.pass robust4.pass robust5.pass \ count1.pass \ once1.pass once2.pass once3.pass once4.pass \ self2.pass \ @@ -398,6 +400,11 @@ mutex8.pass: mutex7.pass mutex8n.pass: mutex7n.pass mutex8e.pass: mutex7e.pass mutex8r.pass: mutex7r.pass +robust1.pass: mutex8r.pass +robust2.pass: mutex8r.pass +robust3.pass: robust2.pass +robust4.pass: robust3.pass +robust5.pass: robust4.pass once1.pass: create1.pass once2.pass: once1.pass once3.pass: once2.pass diff --git a/tests/SIZES.GC b/tests/SIZES.GC index eddaad7..d5ddf36 100755 --- a/tests/SIZES.GC +++ b/tests/SIZES.GC @@ -1,11 +1,11 @@ Sizes of pthreads-win32 structs ------------------------------- pthread_t 8 - ptw32_thread_t 152 + ptw32_thread_t 160 pthread_attr_t_ 28 sem_t_ 12 - pthread_mutex_t_ 24 - pthread_mutexattr_t_ 8 + pthread_mutex_t_ 28 + pthread_mutexattr_t_ 12 pthread_spinlock_t_ 8 pthread_barrier_t_ 36 pthread_barrierattr_t_ 4 diff --git a/tests/SIZES.VC b/tests/SIZES.VC index eddaad7..d5ddf36 100755 --- a/tests/SIZES.VC +++ b/tests/SIZES.VC @@ -1,11 +1,11 @@ Sizes of pthreads-win32 structs ------------------------------- pthread_t 8 - ptw32_thread_t 152 + ptw32_thread_t 160 pthread_attr_t_ 28 sem_t_ 12 - pthread_mutex_t_ 24 - pthread_mutexattr_t_ 8 + pthread_mutex_t_ 28 + pthread_mutexattr_t_ 12 pthread_spinlock_t_ 8 pthread_barrier_t_ 36 pthread_barrierattr_t_ 4 diff --git a/tests/Wmakefile b/tests/Wmakefile index fb988e3..c7e97fb 100644 --- a/tests/Wmakefile +++ b/tests/Wmakefile @@ -94,6 +94,7 @@ PASSES = sizes.pass loadfree.pass & mutex6s.pass mutex6es.pass mutex6rs.pass & mutex7.pass mutex7n.pass mutex7e.pass mutex7r.pass & mutex8.pass mutex8n.pass mutex8e.pass mutex8r.pass & + robust1.pass robust2.pass robust3.pass robust4.pass robust5.pass & count1.pass & once1.pass once2.pass once3.pass once4.pass tsd1.pass & self2.pass & @@ -308,6 +309,11 @@ mutex8.pass: mutex7.pass mutex8n.pass: mutex7n.pass mutex8e.pass: mutex7e.pass mutex8r.pass: mutex7r.pass +robust1.pass: mutex8r.pass +robust2.pass: mutex8r.pass +robust3.pass: robust2.pass +robust4.pass: robust3.pass +robust5.pass: robust4.pass once1.pass: create1.pass once2.pass: once1.pass once3.pass: once2.pass diff --git a/tests/benchtest1.c b/tests/benchtest1.c index ba4abc5..4184719 100644 --- a/tests/benchtest1.c +++ b/tests/benchtest1.c @@ -231,13 +231,29 @@ main (int argc, char *argv[]) * Now we can start the actual tests */ #ifdef PTW32_MUTEX_TYPES - runTest("PTHREAD_MUTEX_DEFAULT (W9x,WNT)", PTHREAD_MUTEX_DEFAULT); + runTest("PTHREAD_MUTEX_DEFAULT", PTHREAD_MUTEX_DEFAULT); - runTest("PTHREAD_MUTEX_NORMAL (W9x,WNT)", PTHREAD_MUTEX_NORMAL); + runTest("PTHREAD_MUTEX_NORMAL", PTHREAD_MUTEX_NORMAL); - runTest("PTHREAD_MUTEX_ERRORCHECK (W9x,WNT)", PTHREAD_MUTEX_ERRORCHECK); + runTest("PTHREAD_MUTEX_ERRORCHECK", PTHREAD_MUTEX_ERRORCHECK); - runTest("PTHREAD_MUTEX_RECURSIVE (W9x,WNT)", PTHREAD_MUTEX_RECURSIVE); + runTest("PTHREAD_MUTEX_RECURSIVE", PTHREAD_MUTEX_RECURSIVE); +#else + runTest("Non-blocking lock", 0); +#endif + + printf( ".............................................................................\n"); + + pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST); + +#ifdef PTW32_MUTEX_TYPES + runTest("PTHREAD_MUTEX_DEFAULT (Robust)", PTHREAD_MUTEX_DEFAULT); + + runTest("PTHREAD_MUTEX_NORMAL (Robust)", PTHREAD_MUTEX_NORMAL); + + runTest("PTHREAD_MUTEX_ERRORCHECK (Robust)", PTHREAD_MUTEX_ERRORCHECK); + + runTest("PTHREAD_MUTEX_RECURSIVE (Robust)", PTHREAD_MUTEX_RECURSIVE); #else runTest("Non-blocking lock", 0); #endif diff --git a/tests/benchtest2.c b/tests/benchtest2.c index 76df9a2..28e1cfe 100644 --- a/tests/benchtest2.c +++ b/tests/benchtest2.c @@ -294,15 +294,31 @@ main (int argc, char *argv[]) * Now we can start the actual tests */ #ifdef PTW32_MUTEX_TYPES - runTest("PTHREAD_MUTEX_DEFAULT (W9x,WNT)", PTHREAD_MUTEX_DEFAULT); + runTest("PTHREAD_MUTEX_DEFAULT", PTHREAD_MUTEX_DEFAULT); - runTest("PTHREAD_MUTEX_NORMAL (W9x,WNT)", PTHREAD_MUTEX_NORMAL); + runTest("PTHREAD_MUTEX_NORMAL", PTHREAD_MUTEX_NORMAL); - runTest("PTHREAD_MUTEX_ERRORCHECK (W9x,WNT)", PTHREAD_MUTEX_ERRORCHECK); + runTest("PTHREAD_MUTEX_ERRORCHECK", PTHREAD_MUTEX_ERRORCHECK); - runTest("PTHREAD_MUTEX_RECURSIVE (W9x,WNT)", PTHREAD_MUTEX_RECURSIVE); + runTest("PTHREAD_MUTEX_RECURSIVE", PTHREAD_MUTEX_RECURSIVE); #else - runTest("Blocking locks", 0); + runTest("Non-blocking lock", 0); +#endif + + printf( ".............................................................................\n"); + + pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST); + +#ifdef PTW32_MUTEX_TYPES + runTest("PTHREAD_MUTEX_DEFAULT (Robust)", PTHREAD_MUTEX_DEFAULT); + + runTest("PTHREAD_MUTEX_NORMAL (Robust)", PTHREAD_MUTEX_NORMAL); + + runTest("PTHREAD_MUTEX_ERRORCHECK (Robust)", PTHREAD_MUTEX_ERRORCHECK); + + runTest("PTHREAD_MUTEX_RECURSIVE (Robust)", PTHREAD_MUTEX_RECURSIVE); +#else + runTest("Non-blocking lock", 0); #endif printf( "=============================================================================\n"); diff --git a/tests/benchtest3.c b/tests/benchtest3.c index faf0fdb..1b6e823 100644 --- a/tests/benchtest3.c +++ b/tests/benchtest3.c @@ -183,13 +183,29 @@ main (int argc, char *argv[]) * Now we can start the actual tests */ #ifdef PTW32_MUTEX_TYPES - runTest("PTHREAD_MUTEX_DEFAULT (W9x,WNT)", PTHREAD_MUTEX_DEFAULT); + runTest("PTHREAD_MUTEX_DEFAULT", PTHREAD_MUTEX_DEFAULT); - runTest("PTHREAD_MUTEX_NORMAL (W9x,WNT)", PTHREAD_MUTEX_NORMAL); + runTest("PTHREAD_MUTEX_NORMAL", PTHREAD_MUTEX_NORMAL); - runTest("PTHREAD_MUTEX_ERRORCHECK (W9x,WNT)", PTHREAD_MUTEX_ERRORCHECK); + runTest("PTHREAD_MUTEX_ERRORCHECK", PTHREAD_MUTEX_ERRORCHECK); - runTest("PTHREAD_MUTEX_RECURSIVE (W9x,WNT)", PTHREAD_MUTEX_RECURSIVE); + runTest("PTHREAD_MUTEX_RECURSIVE", PTHREAD_MUTEX_RECURSIVE); +#else + runTest("Non-blocking lock", 0); +#endif + + printf( ".............................................................................\n"); + + pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST); + +#ifdef PTW32_MUTEX_TYPES + runTest("PTHREAD_MUTEX_DEFAULT (Robust)", PTHREAD_MUTEX_DEFAULT); + + runTest("PTHREAD_MUTEX_NORMAL (Robust)", PTHREAD_MUTEX_NORMAL); + + runTest("PTHREAD_MUTEX_ERRORCHECK (Robust)", PTHREAD_MUTEX_ERRORCHECK); + + runTest("PTHREAD_MUTEX_RECURSIVE (Robust)", PTHREAD_MUTEX_RECURSIVE); #else runTest("Non-blocking lock", 0); #endif diff --git a/tests/benchtest4.c b/tests/benchtest4.c index 53c529b..d64cd4a 100644 --- a/tests/benchtest4.c +++ b/tests/benchtest4.c @@ -164,13 +164,29 @@ main (int argc, char *argv[]) * Now we can start the actual tests */ #ifdef PTW32_MUTEX_TYPES - runTest("PTHREAD_MUTEX_DEFAULT (W9x,WNT)", PTHREAD_MUTEX_DEFAULT); + runTest("PTHREAD_MUTEX_DEFAULT", PTHREAD_MUTEX_DEFAULT); - runTest("PTHREAD_MUTEX_NORMAL (W9x,WNT)", PTHREAD_MUTEX_NORMAL); + runTest("PTHREAD_MUTEX_NORMAL", PTHREAD_MUTEX_NORMAL); - runTest("PTHREAD_MUTEX_ERRORCHECK (W9x,WNT)", PTHREAD_MUTEX_ERRORCHECK); + runTest("PTHREAD_MUTEX_ERRORCHECK", PTHREAD_MUTEX_ERRORCHECK); - runTest("PTHREAD_MUTEX_RECURSIVE (W9x,WNT)", PTHREAD_MUTEX_RECURSIVE); + runTest("PTHREAD_MUTEX_RECURSIVE", PTHREAD_MUTEX_RECURSIVE); +#else + runTest("Non-blocking lock", 0); +#endif + + printf( ".............................................................................\n"); + + pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST); + +#ifdef PTW32_MUTEX_TYPES + runTest("PTHREAD_MUTEX_DEFAULT (Robust)", PTHREAD_MUTEX_DEFAULT); + + runTest("PTHREAD_MUTEX_NORMAL (Robust)", PTHREAD_MUTEX_NORMAL); + + runTest("PTHREAD_MUTEX_ERRORCHECK (Robust)", PTHREAD_MUTEX_ERRORCHECK); + + runTest("PTHREAD_MUTEX_RECURSIVE (Robust)", PTHREAD_MUTEX_RECURSIVE); #else runTest("Non-blocking lock", 0); #endif diff --git a/tests/cancel6d.c b/tests/cancel6d.c index 3fd296a..37f9ca5 100644 --- a/tests/cancel6d.c +++ b/tests/cancel6d.c @@ -136,7 +136,10 @@ main() for (i = 1; i <= NUMTHREADS; i++) { assert(pthread_cancel(t[i]) == 0); - assert(pthread_cancel(t[i]) == 0); + if (pthread_cancel(t[i]) != 0) + { + printf("Second cancelation failed but this is expected sometimes.\n"); + } } /* diff --git a/tests/mutex1e.c b/tests/mutex1e.c index e528107..d32adb3 100644 --- a/tests/mutex1e.c +++ b/tests/mutex1e.c @@ -54,6 +54,8 @@ main() { assert(pthread_mutexattr_init(&mxAttr) == 0); + BEGIN_MUTEX_STALLED_ROBUST(mxAttr) + assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_ERRORCHECK) == 0); assert(mutex == NULL); @@ -70,5 +72,7 @@ main() assert(mutex == NULL); + END_MUTEX_STALLED_ROBUST(mxAttr) + return 0; } diff --git a/tests/mutex1n.c b/tests/mutex1n.c index 74850d6..fcfc134 100644 --- a/tests/mutex1n.c +++ b/tests/mutex1n.c @@ -54,6 +54,8 @@ main() { assert(pthread_mutexattr_init(&mxAttr) == 0); + BEGIN_MUTEX_STALLED_ROBUST(mxAttr) + assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_NORMAL) == 0); assert(mutex == NULL); @@ -70,5 +72,7 @@ main() assert(mutex == NULL); + END_MUTEX_STALLED_ROBUST(mxAttr) + return 0; } diff --git a/tests/mutex1r.c b/tests/mutex1r.c index 0666dec..15083f2 100644 --- a/tests/mutex1r.c +++ b/tests/mutex1r.c @@ -54,6 +54,8 @@ main() { assert(pthread_mutexattr_init(&mxAttr) == 0); + BEGIN_MUTEX_STALLED_ROBUST(mxAttr) + assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE) == 0); assert(mutex == NULL); @@ -70,5 +72,7 @@ main() assert(mutex == NULL); + END_MUTEX_STALLED_ROBUST(mxAttr) + return 0; } diff --git a/tests/mutex4.c b/tests/mutex4.c index b728722..6d36e0a 100644 --- a/tests/mutex4.c +++ b/tests/mutex4.c @@ -65,35 +65,31 @@ main() assert(pthread_mutexattr_init(&ma) == 0); + BEGIN_MUTEX_STALLED_ROBUST(ma) + wasHere = 0; assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_DEFAULT) == 0); assert(pthread_mutex_init(&mutex1, &ma) == 0); assert(pthread_mutex_lock(&mutex1) == 0); - /* - * NORMAL (fast) mutexes don't check ownership. - */ - assert(pthread_create(&t, NULL, unlocker, (void *)(size_t)0) == 0); + assert(pthread_create(&t, NULL, unlocker, (void *)(size_t)(IS_ROBUST?EPERM:0)) == 0); assert(pthread_join(t, NULL) == 0); - assert(pthread_mutex_unlock(&mutex1) == EPERM); + assert(pthread_mutex_unlock(&mutex1) == 0); assert(wasHere == 2); wasHere = 0; assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_NORMAL) == 0); assert(pthread_mutex_init(&mutex1, &ma) == 0); assert(pthread_mutex_lock(&mutex1) == 0); - /* - * NORMAL (fast) mutexes don't check ownership. - */ - assert(pthread_create(&t, NULL, unlocker, (void *) 0) == 0); + assert(pthread_create(&t, NULL, unlocker, (void *)(size_t)(IS_ROBUST?EPERM:0)) == 0); assert(pthread_join(t, NULL) == 0); - assert(pthread_mutex_unlock(&mutex1) == EPERM); + assert(pthread_mutex_unlock(&mutex1) == 0); assert(wasHere == 2); wasHere = 0; assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK) == 0); assert(pthread_mutex_init(&mutex1, &ma) == 0); assert(pthread_mutex_lock(&mutex1) == 0); - assert(pthread_create(&t, NULL, unlocker, (void *) EPERM) == 0); + assert(pthread_create(&t, NULL, unlocker, (void *)(size_t) EPERM) == 0); assert(pthread_join(t, NULL) == 0); assert(pthread_mutex_unlock(&mutex1) == 0); assert(wasHere == 2); @@ -102,10 +98,12 @@ main() assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE) == 0); assert(pthread_mutex_init(&mutex1, &ma) == 0); assert(pthread_mutex_lock(&mutex1) == 0); - assert(pthread_create(&t, NULL, unlocker, (void *) EPERM) == 0); + assert(pthread_create(&t, NULL, unlocker, (void *)(size_t) EPERM) == 0); assert(pthread_join(t, NULL) == 0); assert(pthread_mutex_unlock(&mutex1) == 0); assert(wasHere == 2); + END_MUTEX_STALLED_ROBUST(ma) + return 0; } diff --git a/tests/mutex6e.c b/tests/mutex6e.c index 3f28ee7..908a51b 100644 --- a/tests/mutex6e.c +++ b/tests/mutex6e.c @@ -53,7 +53,7 @@ #include "test.h" -static int lockCount = 0; +static int lockCount; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; @@ -78,6 +78,10 @@ main() int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); + + BEGIN_MUTEX_STALLED_ROBUST(mxAttr) + + lockCount = 0; assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_ERRORCHECK) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_ERRORCHECK); @@ -92,6 +96,9 @@ main() assert(lockCount == 2); assert(pthread_mutex_destroy(&mutex) == 0); + + END_MUTEX_STALLED_ROBUST(mxAttr) + assert(pthread_mutexattr_destroy(&mxAttr) == 0); exit(0); diff --git a/tests/mutex6n.c b/tests/mutex6n.c index 9b4bbb9..9cb309c 100644 --- a/tests/mutex6n.c +++ b/tests/mutex6n.c @@ -49,7 +49,7 @@ #include "test.h" -static int lockCount = 0; +static int lockCount; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; @@ -61,6 +61,7 @@ void * locker(void * arg) /* Should wait here (deadlocked) */ assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); @@ -74,6 +75,10 @@ main() int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); + + BEGIN_MUTEX_STALLED_ROBUST(mxAttr) + + lockCount = 0; assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_NORMAL) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_NORMAL); @@ -82,19 +87,17 @@ main() assert(pthread_create(&t, NULL, locker, NULL) == 0); - Sleep(1000); + Sleep(100); assert(lockCount == 1); - /* - * Should succeed even though we don't own the lock - * because FAST mutexes don't check ownership. - */ - assert(pthread_mutex_unlock(&mutex) == 0); + assert(pthread_mutex_unlock(&mutex) == IS_ROBUST?EPERM:0); + + Sleep (100); - Sleep (1000); + assert(lockCount == IS_ROBUST?1:2); - assert(lockCount == 2); + END_MUTEX_STALLED_ROBUST(mxAttr) exit(0); diff --git a/tests/mutex6r.c b/tests/mutex6r.c index 552f394..9d81ad8 100644 --- a/tests/mutex6r.c +++ b/tests/mutex6r.c @@ -52,7 +52,7 @@ #include "test.h" -static int lockCount = 0; +static int lockCount; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; @@ -77,6 +77,10 @@ main() int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); + + BEGIN_MUTEX_STALLED_ROBUST(mxAttr) + + lockCount = 0; assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_RECURSIVE); @@ -91,6 +95,9 @@ main() assert(lockCount == 2); assert(pthread_mutex_destroy(&mutex) == 0); + + END_MUTEX_STALLED_ROBUST(mxAttr) + assert(pthread_mutexattr_destroy(&mxAttr) == 0); exit(0); diff --git a/tests/mutex7.c b/tests/mutex7.c index 8772b97..4137c35 100644 --- a/tests/mutex7.c +++ b/tests/mutex7.c @@ -57,7 +57,7 @@ void * locker(void * arg) assert(pthread_mutex_trylock(&mutex) == EBUSY); lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); - assert(pthread_mutex_unlock(&mutex) == EPERM); + assert(pthread_mutex_unlock(&mutex) == 0); return 0; } diff --git a/tests/mutex7e.c b/tests/mutex7e.c index 82d941f..80981b3 100644 --- a/tests/mutex7e.c +++ b/tests/mutex7e.c @@ -53,7 +53,7 @@ #include "test.h" -static int lockCount = 0; +static int lockCount; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; @@ -65,7 +65,6 @@ void * locker(void * arg) assert(pthread_mutex_trylock(&mutex) == EBUSY); lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); - assert(pthread_mutex_unlock(&mutex) == EPERM); return (void *) 555; } @@ -78,6 +77,10 @@ main() int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); + + BEGIN_MUTEX_STALLED_ROBUST(mxAttr) + + lockCount = 0; assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_ERRORCHECK) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_ERRORCHECK); @@ -92,6 +95,9 @@ main() assert(lockCount == 2); assert(pthread_mutex_destroy(&mutex) == 0); + + END_MUTEX_STALLED_ROBUST(mxAttr) + assert(pthread_mutexattr_destroy(&mxAttr) == 0); exit(0); diff --git a/tests/mutex7n.c b/tests/mutex7n.c index 174355f..87ba10a 100644 --- a/tests/mutex7n.c +++ b/tests/mutex7n.c @@ -49,7 +49,7 @@ #include "test.h" -static int lockCount = 0; +static int lockCount; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; @@ -61,7 +61,6 @@ void * locker(void * arg) assert(pthread_mutex_trylock(&mutex) == EBUSY); lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); - assert(pthread_mutex_unlock(&mutex) == EPERM); return (void *) 555; } @@ -73,6 +72,10 @@ main() int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); + + BEGIN_MUTEX_STALLED_ROBUST(mxAttr) + + lockCount = 0; assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_NORMAL) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_NORMAL); @@ -81,10 +84,14 @@ main() assert(pthread_create(&t, NULL, locker, NULL) == 0); - Sleep(1000); + Sleep(100); assert(lockCount == 2); + END_MUTEX_STALLED_ROBUST(mxAttr) + + assert(pthread_mutexattr_destroy(&mxAttr) == 0); + exit(0); /* Never reached */ diff --git a/tests/mutex7r.c b/tests/mutex7r.c index 2c1699b..4e4ae8a 100644 --- a/tests/mutex7r.c +++ b/tests/mutex7r.c @@ -52,7 +52,7 @@ #include "test.h" -static int lockCount = 0; +static int lockCount; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; @@ -77,6 +77,10 @@ main() int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); + + BEGIN_MUTEX_STALLED_ROBUST(mxAttr) + + lockCount = 0; assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_RECURSIVE); @@ -91,6 +95,9 @@ main() assert(lockCount == 2); assert(pthread_mutex_destroy(&mutex) == 0); + + END_MUTEX_STALLED_ROBUST(mxAttr) + assert(pthread_mutexattr_destroy(&mxAttr) == 0); exit(0); diff --git a/tests/mutex8e.c b/tests/mutex8e.c index 0e1cbd7..58d7d1e 100644 --- a/tests/mutex8e.c +++ b/tests/mutex8e.c @@ -44,7 +44,7 @@ #include "test.h" #include -static int lockCount = 0; +static int lockCount; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; @@ -80,6 +80,10 @@ main() int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); + + BEGIN_MUTEX_STALLED_ROBUST(mxAttr) + + lockCount = 0; assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_ERRORCHECK) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_ERRORCHECK); @@ -96,6 +100,8 @@ main() assert(pthread_mutex_unlock(&mutex) == 0); + END_MUTEX_STALLED_ROBUST(mxAttr) + return 0; } diff --git a/tests/mutex8n.c b/tests/mutex8n.c index c7141e3..deb9215 100644 --- a/tests/mutex8n.c +++ b/tests/mutex8n.c @@ -44,7 +44,7 @@ #include "test.h" #include -static int lockCount = 0; +static int lockCount; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; @@ -80,6 +80,10 @@ main() int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); + + BEGIN_MUTEX_STALLED_ROBUST(mxAttr) + + lockCount = 0; assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_NORMAL) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_NORMAL); @@ -96,6 +100,8 @@ main() assert(pthread_mutex_unlock(&mutex) == 0); + END_MUTEX_STALLED_ROBUST(mxAttr) + return 0; } diff --git a/tests/mutex8r.c b/tests/mutex8r.c index 58242fe..fe686c5 100644 --- a/tests/mutex8r.c +++ b/tests/mutex8r.c @@ -44,7 +44,7 @@ #include "test.h" #include -static int lockCount = 0; +static int lockCount; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; @@ -80,6 +80,10 @@ main() int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); + + BEGIN_MUTEX_STALLED_ROBUST(mxAttr) + + lockCount = 0; assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_RECURSIVE); @@ -96,6 +100,8 @@ main() assert(pthread_mutex_unlock(&mutex) == 0); + END_MUTEX_STALLED_ROBUST(mxAttr) + return 0; } diff --git a/tests/test.h b/tests/test.h index a6c2b60..639ee55 100644 --- a/tests/test.h +++ b/tests/test.h @@ -113,7 +113,9 @@ const char * error_string[] = { "ENOLCK", "ENOSYS", "ENOTEMPTY", - "EILSEQ" + "EILSEQ", + "EOWNERDEAD", + "ENOTRECOVERABLE" }; /* @@ -152,3 +154,25 @@ int assertE; #e,#o,#r, __FILE__, (int) __LINE__, error_string[assertE]), exit(1), 0)) #endif + +# define BEGIN_MUTEX_STALLED_ROBUST(mxAttr) \ + for(;;) \ + { \ + static int _i=0; \ + static int _robust; \ + pthread_mutexattr_getrobust(&(mxAttr), &_robust); + +# define END_MUTEX_STALLED_ROBUST(mxAttr) \ + printf("Pass %s\n", _robust==PTHREAD_MUTEX_ROBUST?"Robust":"Non-robust"); \ + if (++_i > 1) \ + break; \ + else \ + { \ + pthread_mutexattr_t *pma, *pmaEnd; \ + for(pma = &(mxAttr), pmaEnd = pma + sizeof(mxAttr)/sizeof(pthread_mutexattr_t); \ + pma < pmaEnd; \ + pthread_mutexattr_setrobust(pma++, PTHREAD_MUTEX_ROBUST)); \ + } \ + } + +# define IS_ROBUST (_robust==PTHREAD_MUTEX_ROBUST) diff --git a/w32_CancelableWait.c b/w32_CancelableWait.c index 97e15aa..070633e 100644 --- a/w32_CancelableWait.c +++ b/w32_CancelableWait.c @@ -110,21 +110,22 @@ ptw32_cancelable_wait (HANDLE waitHandle, DWORD timeout) if (sp != NULL) { + ptw32_mcs_local_node_t stateLock; /* * Should handle POSIX and implicit POSIX threads.. * Make sure we haven't been async-canceled in the meantime. */ - (void) pthread_mutex_lock (&sp->cancelLock); + ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); if (sp->state < PThreadStateCanceling) { sp->state = PThreadStateCanceling; sp->cancelState = PTHREAD_CANCEL_DISABLE; - (void) pthread_mutex_unlock (&sp->cancelLock); + ptw32_mcs_lock_release (&stateLock); ptw32_throw (PTW32_EPS_CANCEL); /* Never reached */ } - (void) pthread_mutex_unlock (&sp->cancelLock); + ptw32_mcs_lock_release (&stateLock); } /* Should never get to here. */ -- cgit v1.2.3