From 2fe8aba6a8a4ce09f353f34881c77f93a9c01ca3 Mon Sep 17 00:00:00 2001 From: rpj Date: Fri, 6 May 2011 02:11:50 +0000 Subject: Robust mutexes merged from devel branch --- ANNOUNCE | 35 +++-- Bmakefile | 5 +- ChangeLog | 16 +++ GNUmakefile | 15 +- Makefile | 10 +- NEWS | 55 ++++++-- README.NONPORTABLE | 20 +-- create.c | 79 ++++++----- global.c | 17 ++- implement.h | 72 +++++++--- manual/ChangeLog | 10 +- manual/index.html | 278 +++++++++++++++++++------------------ manual/pthread_getunique_np.html | 76 ++++++++++ manual/pthread_mutex_init.html | 225 ++++++++++++++++++++---------- manual/pthread_mutexattr_init.html | 172 +++++++++++++++-------- mutex.c | 3 + need_errno.h | 4 + nonportable.c | 1 + pthread.h | 40 ++++-- pthread_barrier_destroy.c | 2 +- pthread_barrier_wait.c | 2 +- pthread_cancel.c | 9 +- pthread_delay_np.c | 7 +- pthread_detach.c | 34 ++--- pthread_getunique_np.c | 47 +++++++ pthread_key_create.c | 2 +- pthread_key_delete.c | 40 +++--- pthread_mutex_consistent.c | 190 +++++++++++++++++++++++++ pthread_mutex_destroy.c | 10 +- pthread_mutex_init.c | 52 +++++-- pthread_mutex_lock.c | 232 ++++++++++++++++++++++++------- pthread_mutex_timedlock.c | 222 ++++++++++++++++++++++------- pthread_mutex_trylock.c | 98 ++++++++++--- pthread_mutex_unlock.c | 144 +++++++++++++------ pthread_mutexattr_getrobust.c | 113 +++++++++++++++ pthread_mutexattr_setrobust.c | 119 ++++++++++++++++ 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 | 24 +++- ptw32_MCS_lock.c | 14 +- ptw32_callUserDestroyRoutines.c | 24 ++-- ptw32_new.c | 7 +- ptw32_reuse.c | 2 + ptw32_threadDestroy.c | 3 - ptw32_threadStart.c | 21 +-- ptw32_throw.c | 2 + ptw32_tkAssocCreate.c | 2 +- ptw32_tkAssocDestroy.c | 2 +- tests/Bmakefile | 9 +- tests/ChangeLog | 26 ++++ tests/GNUmakefile | 22 ++- tests/Makefile | 12 +- tests/SIZES.GC | 6 +- tests/SIZES.VC | 6 +- tests/SIZES.VSE | 40 +++--- tests/Wmakefile | 9 +- 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/robust1.c | 141 +++++++++++++++++++ tests/robust2.c | 143 +++++++++++++++++++ tests/robust3.c | 149 ++++++++++++++++++++ tests/robust4.c | 199 ++++++++++++++++++++++++++ tests/robust5.c | 120 ++++++++++++++++ tests/rwlock3.c | 2 +- tests/rwlock4.c | 2 +- tests/rwlock5.c | 2 +- tests/rwlock6.c | 6 +- tests/sequence1.c | 142 +++++++++++++++++++ tests/test.h | 26 +++- w32_CancelableWait.c | 7 +- 90 files changed, 3165 insertions(+), 805 deletions(-) create mode 100755 manual/pthread_getunique_np.html create mode 100755 pthread_getunique_np.c create mode 100755 pthread_mutex_consistent.c create mode 100755 pthread_mutexattr_getrobust.c create mode 100755 pthread_mutexattr_setrobust.c create mode 100755 tests/robust1.c create mode 100755 tests/robust2.c create mode 100755 tests/robust3.c create mode 100755 tests/robust4.c create mode 100755 tests/robust5.c create mode 100755 tests/sequence1.c diff --git a/ANNOUNCE b/ANNOUNCE index 9874931..3fa6232 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -154,12 +154,16 @@ The following functions are implemented: PTHREAD_MUTEX_NORMAL PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_RECURSIVE ) + pthread_mutexattr_getrobust + pthread_mutexattr_setrobust (values: PTHREAD_MUTEX_STALLED + PTHREAD_MUTEX_ROBUST) pthread_mutex_init pthread_mutex_destroy pthread_mutex_lock pthread_mutex_trylock pthread_mutex_timedlock pthread_mutex_unlock + pthread_mutex_consistent --------------------------- Condition Variables @@ -262,6 +266,7 @@ The following functions are implemented: pthread_getw32threadhandle_np pthread_timechange_handler_np pthread_delay_np + pthread_getunique_np pthread_mutexattr_getkind_np pthread_mutexattr_setkind_np (types: PTHREAD_MUTEX_FAST_NP, PTHREAD_MUTEX_ERRORCHECK_NP, @@ -292,16 +297,15 @@ The following functions are implemented: PTHREAD_SPINLOCK_INITIALIZER -The following functions are not implemented: - - --------------------------- - Mutexes - --------------------------- - pthread_mutexattr_getrobust - pthread_mutexattr_setrobust +The library includes two non-API functions for creating cancellation +points in applications and libraries: + + pthreadCancelableWait + pthreadCancelableTimedWait - pthread_mutex_consistent +The following functions are not implemented: + --------------------------- RealTime Scheduling --------------------------- @@ -360,13 +364,6 @@ The following functions are not implemented: rand_r -The library includes two non-API functions for creating cancellation -points in applications and libraries: - - pthreadCancelableWait - pthreadCancelableTimedWait - - Availability ------------ @@ -416,7 +413,7 @@ Mingw using C setjmp/longjmp works. Distribute pthreadGC.dll with your applicati Cygwin: (http://sourceware.cygnus.com/cygwin/) -Developers using Cygwin will not need pthreads-win32 since it has POSIX threads +Developers using Cygwin do not need pthreads-win32 since it has POSIX threads support. Refer to its documentation for details and extent. @@ -429,9 +426,9 @@ Generally: For convenience, the following pre-built files are available on the FTP site (see Availability above): - pthread.h - for POSIX 1c threads - semaphore.h - for POSIX 1b semaphores - sched.h - for POSIX 1b scheduling + pthread.h - for POSIX threads + semaphore.h - for POSIX semaphores + sched.h - for POSIX scheduling pthreadVCE.dll - built with MSVC++ compiler using C++ EH pthreadVCE.lib pthreadVC.dll - built with MSVC compiler using C setjmp/longjmp 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/ChangeLog b/ChangeLog index d60677c..5905825 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2011-03-26 Ross Johnson + + * pthread_getunique_np.c: New non-POSIX interface for compatibility + with some other implementations; returns a 64 bit sequence number + that is unique to each thread in the process. + * pthread.h (pthread_getunique_np): Added. + * global.c: Add global sequence counter for above. + * implement.h: Likewise. + +2011-03-25 Ross Johnson + + * (cancelLock): Convert to an MCS lock and rename to stateLock. + * (threadLock): Likewise. + * (keyLock): Likewise. + * pthread_mutex*.c: First working robust mutexes. + 2011-03-11 Ross Johnson * implement.h (PTW32_INTERLOCKED_*CREMENT macros): increment/decrement diff --git a/GNUmakefile b/GNUmakefile index b357c39..7b15451 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -48,7 +48,7 @@ CP = cp -f #CP = copy # For cross compiling use e.g. -# make CROSS=i386-mingw32msvc- clean GC-inlined +# make CROSS=x86_64-w64-mingw32- clean GC-inlined CROSS = AR = $(CROSS)ar @@ -58,7 +58,7 @@ CXX = $(CROSS)g++ RANLIB = $(CROSS)ranlib RC = $(CROSS)windres -OPT = $(CLEANUP) -O3 -finline-functions +OPT = $(CLEANUP) -O3 # -finline-functions -findirect-inlining DOPT = $(CLEANUP) -g -O0 XOPT = @@ -184,13 +184,17 @@ 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 \ + pthread_getunique_np.o \ pthread_delay_np.o \ pthread_num_processors_np.o \ pthread_win32_attach_detach_np.o \ @@ -338,15 +342,19 @@ 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 \ pthread_mutexattr_getkind_np.c \ pthread_getw32threadhandle_np.c \ + pthread_getunique_np.c \ pthread_delay_np.c \ pthread_num_processors_np.c \ pthread_win32_attach_detach_np.c \ @@ -548,6 +556,7 @@ $(GC_STATIC_STAMP) $(GCD_STATIC_STAMP): $(DLL_INLINED_OBJS) clean: -$(RM) *~ -$(RM) *.i + -$(RM) *.s -$(RM) *.o -$(RM) *.obj -$(RM) *.exe diff --git a/Makefile b/Makefile index 4b790c0..a7fb483 100644 --- a/Makefile +++ b/Makefile @@ -130,13 +130,17 @@ 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 \ + pthread_getunique_np.obj \ pthread_delay_np.obj \ pthread_num_processors_np.obj \ pthread_win32_attach_detach_np.obj \ @@ -280,15 +284,19 @@ 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 \ pthread_mutexattr_getkind_np.c \ pthread_getw32threadhandle_np.c \ + pthread_getunique_np.c \ pthread_delay_np.c \ pthread_num_processors_np.c \ pthread_win32_attach_detach_np.c \ diff --git a/NEWS b/NEWS index 5923901..ebc3e4a 100644 --- a/NEWS +++ b/NEWS @@ -31,11 +31,6 @@ the full test suite, stress tests and benchmarks. New Features ------------ -Dependence on the winsock library is now discretionary via -#define RETAIN_WSALASTERROR in config.h. It is undefined by default unless -WINCE is defined (because I (RJ) am unsure of the dependency there). -- Ramiro Polla - (MSC and GNU builds) The statically linked library now automatically initialises and cleans up on program start/exit, i.e. statically linked applications need not call the routines pthread_win32_process_attach_np() @@ -49,6 +44,19 @@ POSIX TSD (TLS) destructors. See README.NONPORTABLE for descriptions of these routines. - Ramiro Polla +Robust mutexes are implemented within the PROCESS_PRIVATE scope. NOTE that +pthread_mutex_* functions may return different error codes for robust +mutexes than they otherwise do in normal usage, e.g. pthread_mutex_unlock +is required to check ownership for all mutex types when the mutex is +robust, whereas this does not occur for the "normal" non-robust mutex type. +- Ross Johnson + +pthread_getunique_np is implemented for source level compatibility +with some other implementations. This routine returns a 64 bit +sequence number that is uniquely associated with a thread. It can be +used by applications to order or hash POSIX thread handles. +- Ross Johnson + Bug fixes --------- Many more changes for 64 bit systems. @@ -75,11 +83,10 @@ Removed potential NULL pointer reference. - Robert Kindred Removed the requirement that applications restrict the number of threads -calling pthread_barrier_wait() [on the same barrier] to just the barrier -count in order to avoid contention and dead lock. Also reduced the -contention between barrier_wait and barrier_destroy. This change will -have slowed barriers down slightly but halves the number of semaphores -consumed per barrier to one. +calling pthread_barrier_wait to just the barrier count. Also reduced the +contention between barrier_wait and barrier_destroy. This change will have +slowed barriers down slightly but halves the number of semaphores consumed +per barrier to one. - Ross Johnson Fixed a handle leak in sched_[gs]etscheduler. @@ -89,6 +96,34 @@ Removed all of the POSIX re-entrant function compatibility macros from pthread.h Some were simply not semanticly correct. - Igor Lubashev +Threads no longer attempt to pass uncaught exceptions out of thread scope (C++ +and SEH builds only). Uncaught exceptions now cause the thread to exit with +the return code PTHREAD_CANCELED. +- Ross Johnson + +Other changes +------------- +Dependence on the winsock library is now discretionary via +#define RETAIN_WSALASTERROR in config.h. It is undefined by default unless +WINCE is defined (because RJ is unsure of the dependency there). +- Ramiro Polla + +Several static POSIX mutexes used for internal management were replaced by +MCS queue-based locks to reduce resource consumption, in particular use of Win32 +objects. +- Ross Johnson + +New tests +--------- +robust[1-5].c - Robust mutexes +sequence1.c - per-thread unique sequence numbers + +Modified tests and benchtests +----------------------------- +All mutex*.c tests wherever appropriate have been modified to also test +robust mutexes under the same conditions. +Added robust mutex benchtests to benchtest*.c wherever appropriate. + RELEASE 2.8.0 ------------- 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..874b71b 100644 --- a/global.c +++ b/global.c @@ -52,6 +52,11 @@ int ptw32_concurrency = 0; /* What features have been auto-detected */ int ptw32_features = 0; +/* + * Global [process wide] thread sequence Number + */ +unsigned long long ptw32_threadSeqNumber = 0; + /* * Function pointer to QueueUserAPCEx if it exists, otherwise * it will be set at runtime to a substitute routine which cannot unblock @@ -62,37 +67,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..8a27fae 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,35 @@ 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_robust_state_t stateInconsistent; + ptw32_robust_node_t* prev; + ptw32_robust_node_t* next; }; struct pthread_mutexattr_t_ { int pshared; int kind; + int robustness; }; /* @@ -267,9 +299,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 +306,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 +319,7 @@ struct pthread_key_t_ { DWORD key; void (*destructor) (void *); - pthread_mutex_t keyLock; + ptw32_mcs_lock_t keyLock; void *threads; }; @@ -532,6 +561,8 @@ extern pthread_cond_t ptw32_cond_list_tail; extern int ptw32_mutex_default_kind; +extern unsigned long long ptw32_threadSeqNumber; + extern int ptw32_concurrency; extern int ptw32_features; @@ -566,14 +597,9 @@ 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); + void ptw32_robust_mutex_add(pthread_mutex_t* mutex, pthread_t self); + void ptw32_robust_mutex_remove(pthread_mutex_t* mutex, ptw32_thread_t* otp); DWORD ptw32_RegisterCancelation (PAPCFUNC callback, diff --git a/manual/ChangeLog b/manual/ChangeLog index ae3c308..071b847 100644 --- a/manual/ChangeLog +++ b/manual/ChangeLog @@ -1,6 +1,14 @@ +2011-03-26 Ross Johnson + + * pthread_nutex_init.html (robust mutexes): Added + descriptions for newly implemented interface. + * pthread_mutexattr_init.html (robust mutexes): Likewise. + * pthread_getsequence_np.html: New. + * index.html: Updated. + 2008-06-30 Ross Johnson - pthread_setschedparam.html: Fix "see also" links. + * pthread_setschedparam.html: Fix "see also" links. 2005-05-06 Ross Johnson diff --git a/manual/index.html b/manual/index.html index a209dc0..f7b5bc9 100644 --- a/manual/index.html +++ b/manual/index.html @@ -3,144 +3,156 @@ - + - + + + + -

POSIX Threads for Windows – REFERENCE - Pthreads-w32

-

Table of Contents

-

POSIX +

POSIX Threads for Windows – REFERENCE - +Pthreads-w32

+

Table of Contents

+

POSIX threads API reference
Miscellaneous POSIX thread safe routines provided by Pthreads-w32
Non-portable Pthreads-w32 routines
Other

-

POSIX threads API reference

-

pthread_attr_destroy

-

pthread_attr_getdetachstate

-

pthread_attr_getinheritsched

-

pthread_attr_getschedparam

-

pthread_attr_getschedpolicy

-

pthread_attr_getscope

-

pthread_attr_getstackaddr

-

pthread_attr_getstacksize

-

pthread_attr_init

-

pthread_attr_setdetachstate

-

pthread_attr_setinheritsched

-

pthread_attr_setschedparam

-

pthread_attr_setschedpolicy

-

pthread_attr_setscope

-

pthread_attr_setstackaddr

-

pthread_attr_setstacksize

-

pthread_barrierattr_destroy

-

pthread_barrierattr_getpshared

-

pthread_barrierattr_init

-

pthread_barrierattr_setpshared

-

pthread_barrier_destroy

-

pthread_barrier_init

-

pthread_barrier_wait

-

pthread_cancel

-

pthread_cleanup_pop

-

pthread_cleanup_push

-

pthread_condattr_destroy

-

pthread_condattr_getpshared

-

pthread_condattr_init

-

pthread_condattr_setpshared

-

pthread_cond_broadcast

-

pthread_cond_destroy

-

pthread_cond_init

-

pthread_cond_signal

-

pthread_cond_timedwait

-

pthread_cond_wait

-

pthread_create

-

pthread_detach

-

pthread_equal

-

pthread_exit

-

pthread_getconcurrency

-

pthread_getschedparam

-

pthread_getspecific

-

pthread_join

-

pthread_key_create

-

pthread_key_delete

-

pthread_kill

-

pthread_mutexattr_destroy

-

pthread_mutexattr_getkind_np

-

pthread_mutexattr_getpshared

-

pthread_mutexattr_gettype

-

pthread_mutexattr_init

-

pthread_mutexattr_setkind_np

-

pthread_mutexattr_setpshared

-

pthread_mutexattr_settype

-

pthread_mutex_destroy

-

pthread_mutex_init

-

pthread_mutex_lock

-

pthread_mutex_timedlock

-

pthread_mutex_trylock

-

pthread_mutex_unlock

-

pthread_once

-

pthread_rwlockattr_destroy

-

pthread_rwlockattr_getpshared

-

pthread_rwlockattr_init

-

pthread_rwlockattr_setpshared

-

pthread_rwlock_destroy

-

pthread_rwlock_init

-

pthread_rwlock_rdlock

-

pthread_rwlock_timedrdlock

-

pthread_rwlock_timedwrlock

-

pthread_rwlock_tryrdlock

-

pthread_rwlock_trywrlock

-

pthread_rwlock_unlock

-

pthread_rwlock_wrlock

-

pthread_self

-

pthread_setcancelstate

-

pthread_setcanceltype

-

pthread_setconcurrency

-

pthread_setschedparam

-

pthread_setspecific

-

pthread_sigmask

-

pthread_spin_destroy

-

pthread_spin_init

-

pthread_spin_lock

-

pthread_spin_trylock

-

pthread_spin_unlock

-

pthread_testcancel

-

sched_get_priority_max

-

sched_get_priority_min

-

sched_getscheduler

-

sched_setscheduler

-

sched_yield

-

sem_close

-

sem_destroy

-

sem_getvalue

-

sem_init

-

sem_open

-

sem_post

-

sem_post_multiple

-

sem_timedwait

-

sem_trywait

-

sem_unlink

-

sem_wait

-

sigwait

-

Miscellaneous POSIX thread safe -routines provided by Pthreads-w32

-

asctime_r

-

ctime_r

-

gmtime_r

-

localtime_r

-

rand_r

-

Non-portable Pthreads-w32 routines

-

pthreadCancelableTimedWait

-

pthreadCancelableWait

-

pthread_delay_np

-

pthread_getw32threadhandle_np

-

pthread_num_processors_np

-

pthread_win32_test_features_np

-

pthread_timechange_handler_np

-

pthread_win32_process_attach_np

-

pthread_win32_process_detach_np

-

pthread_win32_thread_attach_np

-

pthread_win32_thread_detach_np

-

Other

-

Portability +

POSIX threads API +reference

+

pthread_attr_destroy

+

pthread_attr_getdetachstate

+

pthread_attr_getinheritsched

+

pthread_attr_getschedparam

+

pthread_attr_getschedpolicy

+

pthread_attr_getscope

+

pthread_attr_getstackaddr

+

pthread_attr_getstacksize

+

pthread_attr_init

+

pthread_attr_setdetachstate

+

pthread_attr_setinheritsched

+

pthread_attr_setschedparam

+

pthread_attr_setschedpolicy

+

pthread_attr_setscope

+

pthread_attr_setstackaddr

+

pthread_attr_setstacksize

+

pthread_barrierattr_destroy

+

pthread_barrierattr_getpshared

+

pthread_barrierattr_init

+

pthread_barrierattr_setpshared

+

pthread_barrier_destroy

+

pthread_barrier_init

+

pthread_barrier_wait

+

pthread_cancel

+

pthread_cleanup_pop

+

pthread_cleanup_push

+

pthread_condattr_destroy

+

pthread_condattr_getpshared

+

pthread_condattr_init

+

pthread_condattr_setpshared

+

pthread_cond_broadcast

+

pthread_cond_destroy

+

pthread_cond_init

+

pthread_cond_signal

+

pthread_cond_timedwait

+

pthread_cond_wait

+

pthread_create

+

pthread_detach

+

pthread_equal

+

pthread_exit

+

pthread_getconcurrency

+

pthread_getschedparam

+

pthread_getunique_np

+

pthread_getspecific

+

pthread_join

+

pthread_key_create

+

pthread_key_delete

+

pthread_kill

+

pthread_mutexattr_destroy

+

pthread_mutexattr_getkind_np

+

pthread_mutexattr_getpshared

+

pthread_mutexattr_getrobust

+

pthread_mutexattr_gettype

+

pthread_mutexattr_init

+

pthread_mutexattr_setkind_np

+

pthread_mutexattr_setpshared

+

pthread_mutexattr_setrobust

+

pthread_mutexattr_settype

+

pthread_mutex_consistent

+

pthread_mutex_destroy

+

pthread_mutex_init

+

pthread_mutex_lock

+

pthread_mutex_timedlock

+

pthread_mutex_trylock

+

pthread_mutex_unlock

+

pthread_once

+

pthread_rwlockattr_destroy

+

pthread_rwlockattr_getpshared

+

pthread_rwlockattr_init

+

pthread_rwlockattr_setpshared

+

pthread_rwlock_destroy

+

pthread_rwlock_init

+

pthread_rwlock_rdlock

+

pthread_rwlock_timedrdlock

+

pthread_rwlock_timedwrlock

+

pthread_rwlock_tryrdlock

+

pthread_rwlock_trywrlock

+

pthread_rwlock_unlock

+

pthread_rwlock_wrlock

+

pthread_self

+

pthread_setcancelstate

+

pthread_setcanceltype

+

pthread_setconcurrency

+

pthread_setschedparam

+

pthread_setspecific

+

pthread_sigmask

+

pthread_spin_destroy

+

pthread_spin_init

+

pthread_spin_lock

+

pthread_spin_trylock

+

pthread_spin_unlock

+

pthread_testcancel

+

sched_get_priority_max

+

sched_get_priority_min

+

sched_getscheduler

+

sched_setscheduler

+

sched_yield

+

sem_close

+

sem_destroy

+

sem_getvalue

+

sem_init

+

sem_open

+

sem_post

+

sem_post_multiple

+

sem_timedwait

+

sem_trywait

+

sem_unlink

+

sem_wait

+

sigwait

+

Non-portable +Pthreads-w32 routines

+

pthreadCancelableTimedWait

+

pthreadCancelableWait

+

pthread_delay_np

+

pthread_getw32threadhandle_np

+

pthread_num_processors_np

+

pthread_win32_test_features_np

+

pthread_timechange_handler_np

+

pthread_win32_process_attach_np

+

pthread_win32_process_detach_np

+

pthread_win32_thread_attach_np

+

pthread_win32_thread_detach_np

+

Other

+

Portability issues

- + \ No newline at end of file diff --git a/manual/pthread_getunique_np.html b/manual/pthread_getunique_np.html new file mode 100755 index 0000000..182ce73 --- /dev/null +++ b/manual/pthread_getunique_np.html @@ -0,0 +1,76 @@ + + + + + PTHREAD_GETW32THREADHANDLE_NP manual page + + + + + + + + + + +

POSIX Threads for Windows – REFERENCE - +Pthreads-w32

+

Reference Index

+

Table of Contents

+

Name

+

pthread_getunique_np – get the +unique sequence number associated with a thread

+

Synopsis

+

#include <pthread.h> +

+

unsigned long long pthread_getunique_np(pthread_t thread);

+

Description

+

Returns the unique 64 bit +sequence number assigned to thread.

+

In Pthreads-win32:

+
    +
  • the value returned is not reused after the thread terminates + so it is unique for the life of the process

    +
  • Windows native threads may obtain their own POSIX thread + sequence number by first retrieving their pthread_t handle + via pthread_self to use as the thread argument.

    +
+

This function was added for source code compatibility with some +other POSIX threads implementations.

+

Cancellation

+

None.

+

Return Value

+

pthread_getunique_np returns the unique sequence number for +thread.

+

Errors

+

None.

+

Author

+

Ross Johnson for use with Pthreads-w32.

+
+

Table of Contents

+ + + \ No newline at end of file diff --git a/manual/pthread_mutex_init.html b/manual/pthread_mutex_init.html index f9982cf..cdb333e 100644 --- a/manual/pthread_mutex_init.html +++ b/manual/pthread_mutex_init.html @@ -3,22 +3,37 @@ PTHREAD_MUTEX(3) manual page - + - + + + + + -

POSIX Threads for Windows – REFERENCE - Pthreads-w32

+

POSIX Threads for Windows – REFERENCE - +Pthreads-w32

Reference Index

Table of Contents

-

Name

+

Name

pthread_mutex_init, pthread_mutex_lock, pthread_mutex_trylock, -pthread_mutex_timedlock, pthread_mutex_unlock, pthread_mutex_destroy -- operations on mutexes +pthread_mutex_timedlock, pthread_mutex_unlock, +pthread_mutex_consistent, pthread_mutex_destroy - operations on +mutexes

-

Synopsis

+

Synopsis

#include <pthread.h>

#include <time.h>

@@ -49,9 +64,11 @@ const pthread_mutexattr_t *
mutexattr);

int pthread_mutex_unlock(pthread_mutex_t *mutex);

+

int pthread_mutex_consistent(pthread_mutex_t *mutex); +

int pthread_mutex_destroy(pthread_mutex_t *mutex);

-

Description

+

Description

A mutex is a MUTual EXclusion device, and is useful for protecting shared data structures from concurrent modifications, and implementing critical sections and monitors. @@ -76,16 +93,22 @@ for more information on mutex attributes. statically, using the constants PTHREAD_MUTEX_INITIALIZER (for normal “fast” mutexes), PTHREAD_RECURSIVE_MUTEX_INITIALIZER (for recursive mutexes), and PTHREAD_ERRORCHECK_MUTEX_INITIALIZER -(for error checking mutexes). In -the Pthreads-w32 implementation, an application should still -call pthread_mutex_destroy at some point to ensure that any +(for error checking mutexes). In +the Pthreads-w32 implementation, +an application should still call pthread_mutex_destroy +at some point to ensure that any resources consumed by the mutex are released.

+

Any mutex type can be +initialized as a robust mutex. +See pthread_mutexattr_init(3) +for more information as well as the +section Robust Mutexes +below.

pthread_mutex_lock locks the given mutex. If the mutex is currently unlocked, it becomes locked and owned by the calling thread, and pthread_mutex_lock returns immediately. If the mutex is already locked by another thread, pthread_mutex_lock -suspends the calling thread until the mutex is unlocked. -

+suspends the calling thread until the mutex is unlocked.

If the mutex is already locked by the calling thread, the behavior of pthread_mutex_lock depends on the type of the mutex. If the mutex is of the “normal” type, the calling thread is suspended @@ -101,15 +124,18 @@ be performed before the mutex returns to the unlocked state.

pthread_mutex_trylock behaves identically to pthread_mutex_lock, except that it does not block the calling thread if the mutex is already locked by another thread (or by the -calling thread in the case of a “normal” mutex). Instead, -pthread_mutex_trylock returns immediately with the error code -EBUSY. +calling thread in the case of a “normal” or “errorcheck” +mutex). Instead, pthread_mutex_trylock returns immediately +with the error code EBUSY.

pthread_mutex_timedlock behaves identically to pthread_mutex_lock, except that if it cannot acquire the lock before the abs_timeout time, the call returns with the error code ETIMEDOUT. If the mutex can be locked immediately it is, and the abs_timeout parameter is ignored.

+

pthread_mutex_consistent may only be called for +PTHREAD_MUTEX_ROBUST mutexes. It simply marks the mutex as +consistent. See Robust Mutexes below.

pthread_mutex_unlock unlocks the given mutex. The mutex is assumed to be locked and owned by the calling thread on entrance to pthread_mutex_unlock. If the mutex is of the “normal” @@ -117,19 +143,53 @@ type, pthread_mutex_unlock always returns it to the unlocked state. If it is of the ‘‘recursive’’ type, it decrements the locking count of the mutex (number of pthread_mutex_lock operations performed on it by the calling thread), and only when this -count reaches zero is the mutex actually unlocked. -

+count reaches zero is the mutex actually unlocked. In Pthreads-win32, +non-robust normal or default mutex types do not check the owner of +the mutex. For all types of robust mutexes the owner is checked and +an error code is returned if the calling thread does not own the +mutex.

On ‘‘error checking’’ mutexes, pthread_mutex_unlock actually checks at run-time that the mutex is locked on entrance, and that it was locked by the same thread that is now calling pthread_mutex_unlock. If these conditions are not met, an error code is returned and the mutex remains unchanged. ‘‘Normal’’ -mutexes perform no such checks, thus allowing a locked mutex to be -unlocked by a thread other than its owner. This is non-portable -behavior and is not meant to be used as a feature.

+[non-robust] mutexes perform no such checks, thus allowing a locked +mutex to be unlocked by a thread other than its owner. This is +non-portable behavior and is not meant to be used as a feature.

pthread_mutex_destroy destroys a mutex object, freeing the resources it might hold. The mutex must be unlocked on entrance.

-

Cancellation

+

Robust Mutexes

+

If the mutex is PTHREAD_MUTEX_ROBUST and the owning thread +terminates without unlocking the mutex the implementation will wake +one waiting thread, if any. The next thread to acquire the mutex will +receive the error code EOWNERDEAD, +in which case that thread should if possible ensure that the state +protected by the mutex is consistent and then call +pthread_mutex_consistent before +unlocking. The mutex may then be used normally from then on.

+

If the thread cannot recover the +state then it must call pthread_mutex_unlock +without calling pthread_mutex_consistent. +This will mark the mutex as unusable and wake all currently waiting +threads with the return code ENOTRECOVERABLE. +The error indicates that the mutex is no longer usable and any +threads that receive this error code from any lock operation have not +acquired the mutex. The mutex can be made consistent by calling +pthread_mutex_destroy to +uninitialize the mutex, and calling pthread_mutex_int +to reinitialize the mutex. However, +the state that was protected by the mutex remains inconsistent and +some form of application recovery is required.

+

If a thread that receives the +EOWNERDEAD error code +itself terminates without unlocking the mutex then this behaviour +repeats for the next acquiring thread.

+

Applications must ensure that +they check the return values from all calls targeting robust mutexes.

+

Robust mutexes are slower because they +require some additional overhead, however they are not very much +slower than the non-robust recursive type.

+

Cancellation

None of the mutex functions is a cancellation point, not even pthread_mutex_lock, in spite of the fact that it can suspend a thread for arbitrary durations. This way, the status of mutexes at @@ -138,46 +198,56 @@ unlock precisely those mutexes that need to be unlocked before the thread stops executing. Consequently, threads using deferred cancellation should never hold a mutex for extended periods of time.

-

Async-signal Safety

+

Async-signal Safety

The mutex functions are not async-signal safe. What this means is that they should not be called from a signal handler. In particular, calling pthread_mutex_lock or pthread_mutex_unlock from a signal handler may deadlock the calling thread.

-

Return Value

+

Return Value

pthread_mutex_init always returns 0. The other mutex functions return 0 on success and a non-zero error code on error.

-

Errors

+

Errors

The pthread_mutex_lock function returns the following error code on error:

-
EINVAL -
+
EINVAL
the mutex has not been properly initialized. -
- EDEADLK -
+
+ EDEADLK
the mutex is already locked by the calling thread (‘‘error checking’’ mutexes only). -
-
-

-The pthread_mutex_trylock function returns the following error -codes on error: -

-
-
-
EBUSY -
+
+ EOWNERDEAD
+ the robust mutex is now locked by the calling thread after the + previous owner terminated without unlocking it.
+ ENOTRECOVERABLE
+ the robust mutex is not locked and is no longer usable after the + previous owner unlocked it without calling + pthread_mutex_consistent.
+
+ The pthread_mutex_trylock function returns the following + error codes on error: +
+
+ EBUSY +
the mutex could not be acquired because it was currently locked. -
+
EINVAL -
+
the mutex has not been properly initialized. -
+
+ EOWNERDEAD
+ the robust mutex is now locked by the calling thread after the + previous owner terminated without unlocking it.
+ ENOTRECOVERABLE
+ the robust mutex is not locked and is no longer usable after the + previous owner unlocked it without calling + pthread_mutex_consistent.

The pthread_mutex_timedlock function returns the following @@ -185,15 +255,22 @@ error codes on error:

-
ETIMEDOUT -
+
ETIMEDOUT +
the mutex could not be acquired before the abs_timeout time arrived. -
+
EINVAL -
+
the mutex has not been properly initialized. -
+
+ EOWNERDEAD
+ the robust mutex is now locked by the calling thread after the + previous owner terminated without unlocking it.
+ ENOTRECOVERABLE
+ the robust mutex is not locked and is no longer usable after the + previous owner unlocked it without calling + pthread_mutex_consistent.

The pthread_mutex_unlock function returns the following error @@ -201,12 +278,12 @@ code on error:

-
EINVAL -
+
EINVAL +
the mutex has not been properly initialized. -
+
EPERM -
+
the calling thread does not own the mutex (‘‘error checking’’ mutexes only).
@@ -217,61 +294,63 @@ code on error:

-
EBUSY -
+
EBUSY +
the mutex is currently locked.
-

+

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

-

See Also

+

See Also

pthread_mutexattr_init(3) , pthread_mutexattr_settype(3) , pthread_cancel(3) .

-

Example

+

Example

A shared global variable x can be protected by a mutex as follows:

-
int x;
-pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+
int x;
+pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
All accesses and modifications to x should be bracketed by calls to pthread_mutex_lock and pthread_mutex_unlock as follows:
-
pthread_mutex_lock(&mut);
+
pthread_mutex_lock(&mut);
 /* operate on x */
 pthread_mutex_unlock(&mut);

-
Table of -Contents
+
Table +of Contents
- + \ No newline at end of file diff --git a/manual/pthread_mutexattr_init.html b/manual/pthread_mutexattr_init.html index f3df993..f69599b 100644 --- a/manual/pthread_mutexattr_init.html +++ b/manual/pthread_mutexattr_init.html @@ -3,22 +3,32 @@ PTHREAD_MUTEXATTR(3) manual page - + - + + + -

POSIX Threads for Windows – REFERENCE - Pthreads-w32

+

POSIX Threads for Windows – REFERENCE - +Pthreads-w32

Reference Index

Table of Contents

-

Name

+

Name

pthread_mutexattr_init, pthread_mutexattr_destroy, pthread_mutexattr_settype, pthread_mutexattr_gettype - mutex creation attributes

-

Synopsis

+

Synopsis

#include <pthread.h>

int pthread_mutexattr_init(pthread_mutexattr_t *attr); @@ -37,7 +47,13 @@ int type);

int pthread_mutexattr_getkind_np(const pthread_mutexattr_t *attr, int *type);

-

Description

+

int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr, +int robust); +

+

int pthread_mutexattr_getrobust(pthread_mutexattr_t *attr, +int *robust); +

+

Description

Mutex attributes can be specified at mutex creation time, by passing a mutex attribute object as second argument to pthread_mutex_init(3) . @@ -50,12 +66,27 @@ attributes.

pthread_mutexattr_destroy destroys a mutex attribute object, which must not be reused until it is reinitialized.

+

pthread_mutexattr_settype sets the mutex type attribute in +attr to the value specified by type. +

+

pthread_mutexattr_gettype retrieves the current value of +the mutex kind attribute in attr and stores it in the location +pointed to by type. +

+

Pthreads-w32 also recognises the following equivalent +functions that are used in Linux:

+

pthread_mutexattr_setkind_np is an alias for +pthread_mutexattr_settype. +

+

pthread_mutexattr_getkind_np is +an alias for pthread_mutexattr_gettype. +

The following mutex types are supported:

-

PTHREAD_MUTEX_NORMAL - for +

PTHREAD_MUTEX_NORMAL - for ‘‘fast’’ mutexes.

-

PTHREAD_MUTEX_RECURSIVE - for +

PTHREAD_MUTEX_RECURSIVE - for ‘‘recursive’’ mutexes.

-

PTHREAD_MUTEX_ERRORCHECK - for +

PTHREAD_MUTEX_ERRORCHECK - for ‘‘error checking’’ mutexes.

The mutex type determines what happens if a thread attempts to lock a mutex it already owns with pthread_mutex_lock(3) @@ -75,83 +106,102 @@ state.

The default mutex type is PTHREAD_MUTEX_NORMAL

Pthreads-w32 also recognises the following equivalent types that are used by Linux:

-

PTHREAD_MUTEX_FAST_NP +

PTHREAD_MUTEX_FAST_NP – equivalent to PTHREAD_MUTEX_NORMAL

-

PTHREAD_MUTEX_RECURSIVE_NP

-

PTHREAD_MUTEX_ERRORCHECK_NP

-

pthread_mutexattr_settype sets the mutex type attribute in -attr to the value specified by type. -

-

pthread_mutexattr_gettype retrieves the current value of -the mutex kind attribute in attr and stores it in the location -pointed to by type. -

-

Pthreads-w32 also recognises the following equivalent -functions that are used in Linux:

-

pthread_mutexattr_setkind_np is an alias for -pthread_mutexattr_settype. -

-

pthread_mutexattr_getkind_np is -an alias for pthread_mutexattr_gettype. -

-

Return Value

-

pthread_mutexattr_init, pthread_mutexattr_destroy -and pthread_mutexattr_gettype always return 0. -

-

pthread_mutexattr_settype returns 0 on success and a -non-zero error code on error. -

-

Errors

-

On error, pthread_mutexattr_settype returns the following -error code: -

+

PTHREAD_MUTEX_RECURSIVE_NP

+

PTHREAD_MUTEX_ERRORCHECK_NP

+

pthread_mutexattr_setrobust +sets the robustness attribute to the value given by robust.

+

pthread_mutexattr_getrobust +returns the current robustness value to the location given by +*robust.

+

The possible values for robust +are:

+

PTHREAD_MUTEX_STALLED +- when the owner of the mutex terminates without unlocking the mutex, +all subsequent calls to pthread_mutex_*lock() are blocked from +progress in an unspecified manner.

+

PTHREAD_MUTEX_ROBUST +- when the owner of the mutex terminates without unlocking the mutex, +the mutex is unlocked. The next owner of this mutex acquires the +mutex with an error return of EOWNERDEAD.

+

Return Value

+

On success all functions return +0, otherwise they return an error code as follows:

+

pthread_mutexattr_init

+

ENOMEM +- insufficient memory for attr.

+

pthread_mutexattr_destroy

+

EINVAL +- attr +is invalid.

+

pthread_mutexattr_gettype

+

EINVAL +- attr +is invalid.

+

pthread_mutexattr_settype

-
EINVAL -
- type is none of:
PTHREAD_MUTEX_NORMAL, - PTHREAD_MUTEX_FAST_NP,
PTHREAD_MUTEX_RECURSIVE, - PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK
, - PTHREAD_MUTEX_ERRORCHECK_NP +
+
+
EINVAL - attr + is invalid or type + is none of:
+
+
+ PTHREAD_MUTEX_NORMAL
PTHREAD_MUTEX_FAST_NP
PTHREAD_MUTEX_RECURSIVE
PTHREAD_MUTEX_RECURSIVE_NP
PTHREAD_MUTEX_ERRORCHECK
PTHREAD_MUTEX_ERRORCHECK_NP
+
+
+
+
+
-

-Author

+

+pthread_mutexattr_getrobust

+

EINVAL +– attr +or robust +is invalid.

+

pthread_mutexattr_setrobust

+

EINVAL +– attr +or robust +is invalid.

+

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

-

See Also

+

See Also

pthread_mutex_init(3) , pthread_mutex_lock(3) , pthread_mutex_unlock(3) .

-

Notes

+

Notes

For speed, Pthreads-w32 never checks the thread ownership -of mutexes of type PTHREAD_MUTEX_NORMAL (or +of non-robust mutexes of type PTHREAD_MUTEX_NORMAL (or PTHREAD_MUTEX_FAST_NP) when performing operations on the mutex. It is therefore possible for one thread to lock such a mutex and another to unlock it.

-

When developing code, it is a -common precaution to substitute the error checking type, and drop in -the normal type for release if the extra performance is required.

+

When developing code, it is a common +precaution to substitute the error checking type, then drop in the +normal type for release if the extra performance is required.


Table of Contents

- + \ No newline at end of file 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/nonportable.c b/nonportable.c index 6c2a990..742cb96 100644 --- a/nonportable.c +++ b/nonportable.c @@ -40,6 +40,7 @@ #include "pthread_mutexattr_setkind_np.c" #include "pthread_mutexattr_getkind_np.c" #include "pthread_getw32threadhandle_np.c" +#include "pthread_getunique_np.c" #include "pthread_delay_np.c" #include "pthread_num_processors_np.c" #include "pthread_win32_attach_detach_np.c" diff --git a/pthread.h b/pthread.h index 294fe4c..d4b5899 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 */ @@ -1153,6 +1176,7 @@ PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * */ PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval); PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void); +PTW32_DLLPORT unsigned long long PTW32_CDECL pthread_getunique_np(pthread_t thread); /* * Useful if an application wants to statically link 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_getunique_np.c b/pthread_getunique_np.c new file mode 100755 index 0000000..f81fc61 --- /dev/null +++ b/pthread_getunique_np.c @@ -0,0 +1,47 @@ +/* + * pthread_getunique_np.c + * + * Description: + * This translation unit implements non-portable thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * + */ +unsigned long long +pthread_getunique_np (pthread_t thread) +{ + return ((ptw32_thread_t*)thread.p)->seqNumber; +} 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_consistent.c b/pthread_mutex_consistent.c new file mode 100755 index 0000000..b5dcc15 --- /dev/null +++ b/pthread_mutex_consistent.c @@ -0,0 +1,190 @@ +/* + * pthread_mutex_consistent.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* + * From the Sun Multi-threaded Programming Guide + * + * robustness defines the behavior when the owner of the mutex terminates without unlocking the + * mutex, usually because its process terminated abnormally. The value of robustness that is + * defined in pthread.h is PTHREAD_MUTEX_ROBUST or PTHREAD_MUTEX_STALLED. The + * default value is PTHREAD_MUTEX_STALLED . + * ■ PTHREAD_MUTEX_STALLED + * When the owner of the mutex terminates without unlocking the mutex, all subsequent calls + * to pthread_mutex_lock() are blocked from progress in an unspecified manner. + * ■ PTHREAD_MUTEX_ROBUST + * When the owner of the mutex terminates without unlocking the mutex, the mutex is + * unlocked. The next owner of this mutex acquires the mutex with an error return of + * EOWNERDEAD. + * Note – Your application must always check the return code from pthread_mutex_lock() for + * a mutex initialized with the PTHREAD_MUTEX_ROBUST attribute. + * ■ The new owner of this mutex should make the state protected by the mutex consistent. + * This state might have been left inconsistent when the previous owner terminated. + * ■ If the new owner is able to make the state consistent, call + * pthread_mutex_consistent() for the mutex before unlocking the mutex. This + * marks the mutex as consistent and subsequent calls to pthread_mutex_lock() and + * pthread_mutex_unlock() will behave in the normal manner. + * ■ If the new owner is not able to make the state consistent, do not call + * pthread_mutex_consistent() for the mutex, but unlock the mutex. + * All waiters are woken up and all subsequent calls to pthread_mutex_lock() fail to + * acquire the mutex. The return code is ENOTRECOVERABLE. The mutex can be made + * consistent by calling pthread_mutex_destroy() to uninitialize the mutex, and calling + * pthread_mutex_int() to reinitialize the mutex.However, the state that was protected + * by the mutex remains inconsistent and some form of application recovery is required. + * ■ If the thread that acquires the lock with EOWNERDEAD terminates without unlocking the + * mutex, the next owner acquires the lock with an EOWNERDEAD return code. + */ +#ifndef _UWIN +/*# include */ +#endif +#include "pthread.h" +#include "implement.h" + +INLINE +int +ptw32_robust_mutex_inherit(pthread_mutex_t * mutex) +{ + int result; + pthread_mutex_t mx = *mutex; + ptw32_robust_node_t* robust = mx->robustNode; + + switch (PTW32_INTERLOCKED_COMPARE_EXCHANGE( + (LPLONG)&robust->stateInconsistent, + (LONG)PTW32_ROBUST_INCONSISTENT, + -1L /* The terminating thread sets this */)) + { + case -1L: + result = EOWNERDEAD; + break; + case (LONG)PTW32_ROBUST_NOTRECOVERABLE: + result = ENOTRECOVERABLE; + break; + default: + result = 0; + break; + } + + return result; +} + +/* + * The next two internal support functions depend on only being + * called by the thread that owns the robust mutex. This enables + * us to avoid additional locks. + * Any mutex currently in the thread's robust mutex list is held + * by the thread, again eliminating the need for locks. + * The forward/backward links allow the thread to unlock mutexes + * in any order, not necessarily the reverse locking order. + * This is all possible because it is an error if a thread that + * does not own the [robust] mutex attempts to unlock it. + */ + +INLINE +void +ptw32_robust_mutex_add(pthread_mutex_t* mutex, pthread_t self) +{ + ptw32_robust_node_t** list; + pthread_mutex_t mx = *mutex; + ptw32_thread_t* tp = (ptw32_thread_t*)self.p; + ptw32_robust_node_t* robust = mx->robustNode; + + list = &tp->robustMxList; + mx->ownerThread = self; + if (NULL == *list) + { + robust->prev = NULL; + robust->next = NULL; + *list = robust; + } + else + { + robust->prev = NULL; + robust->next = *list; + (*list)->prev = robust; + *list = robust; + } +} + +INLINE +void +ptw32_robust_mutex_remove(pthread_mutex_t* mutex, ptw32_thread_t* otp) +{ + ptw32_robust_node_t** list; + pthread_mutex_t mx = *mutex; + ptw32_robust_node_t* robust = mx->robustNode; + + list = &(((ptw32_thread_t*)mx->ownerThread.p)->robustMxList); + mx->ownerThread.p = otp; + if (robust->next != NULL) + { + robust->next->prev = robust->prev; + } + if (robust->prev != NULL) + { + robust->prev->next = robust->next; + } + if (*list == robust) + { + *list = robust->next; + } +} + + +int +pthread_mutex_consistent (pthread_mutex_t* mutex) +{ + pthread_mutex_t mx = *mutex; + int result = 0; + + /* + * Let the system deal with invalid pointers. + */ + if (mx == NULL) + { + return EINVAL; + } + + if (mx->kind >= 0 + || (LONG)PTW32_ROBUST_INCONSISTENT != PTW32_INTERLOCKED_COMPARE_EXCHANGE( + (LPLONG)&mx->robustNode->stateInconsistent, + (LONG)PTW32_ROBUST_CONSISTENT, + (LONG)PTW32_ROBUST_INCONSISTENT)) + { + result = EINVAL; + } + + return (result); +} + 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..daf805e 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,33 @@ 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->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..ba410a6 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,200 @@ 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)) + && (LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) -1) != 0) + { + 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) + { + /* + * 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 + { + 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; + /* + * 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 + { + 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)) + && (LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) -1) != 0) + { + 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; + /* + * 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); + } + } + } + } + } } return (result); } + diff --git a/pthread_mutex_timedlock.c b/pthread_mutex_timedlock.c index a238552..3f759b5 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,193 @@ 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)) + && (LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) -1) != 0) + { + 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) + { + /* + * 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 + { + 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; + /* + * 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 + { + 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)) + && (LONG) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG) &mx->lock_idx, + (LONG) -1) != 0) + { + 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; + /* + * 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); + } + } + } + } + } + } + + return result; } diff --git a/pthread_mutex_trylock.c b/pthread_mutex_trylock.c index 50e8bc6..6fcff75 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,90 @@ 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; + } + ptw32_robust_mutex_add(mutex, self); + } 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))) + { + mx->recursive_count = 1; + ptw32_robust_mutex_add(mutex, self); + } + else + { + if (0 == result) + { + result = EBUSY; + } + } + } + } } return (result); diff --git a/pthread_mutex_unlock.c b/pthread_mutex_unlock.c index 9ebe4e3..5cd51af 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,115 @@ 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) + { + ptw32_robust_mutex_remove(mutex, 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 + { + if (kind != PTHREAD_MUTEX_RECURSIVE + || 0 == --mx->recursive_count) + { + ptw32_robust_mutex_remove(mutex, 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 + else if (mx != PTHREAD_MUTEX_INITIALIZER) { result = EINVAL; } diff --git a/pthread_mutexattr_getrobust.c b/pthread_mutexattr_getrobust.c new file mode 100755 index 0000000..be00483 --- /dev/null +++ b/pthread_mutexattr_getrobust.c @@ -0,0 +1,113 @@ +/* + * pthread_mutexattr_getrobust.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutexattr_getrobust (const pthread_mutexattr_t * attr, int * robust) + /* + * ------------------------------------------------------ + * + * DOCPUBLIC + * The pthread_mutexattr_setrobust() and + * pthread_mutexattr_getrobust() functions respectively set and + * get the mutex robust attribute. This attribute is set in the + * robust parameter to these functions. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * robust + * must be one of: + * + * PTHREAD_MUTEX_STALLED + * + * PTHREAD_MUTEX_ROBUST + * + * DESCRIPTION + * The pthread_mutexattr_setrobust() and + * pthread_mutexattr_getrobust() functions respectively set and + * get the mutex robust attribute. This attribute is set in the + * robust parameter to these functions. The default value of the + * robust attribute is PTHREAD_MUTEX_STALLED. + * + * The robustness of mutex is contained in the robustness attribute + * of the mutex attributes. Valid mutex robustness values are: + * + * PTHREAD_MUTEX_STALLED + * No special actions are taken if the owner of the mutex is + * terminated while holding the mutex lock. This can lead to + * deadlocks if no other thread can unlock the mutex. + * This is the default value. + * + * PTHREAD_MUTEX_ROBUST + * If the process containing the owning thread of a robust mutex + * terminates while holding the mutex lock, the next thread that + * acquires the mutex shall be notified about the termination by + * the return value [EOWNERDEAD] from the locking function. If the + * owning thread of a robust mutex terminates while holding the mutex + * lock, the next thread that acquires the mutex may be notified + * about the termination by the return value [EOWNERDEAD]. The + * notified thread can then attempt to mark the state protected by + * the mutex as consistent again by a call to + * pthread_mutex_consistent(). After a subsequent successful call to + * pthread_mutex_unlock(), the mutex lock shall be released and can + * be used normally by other threads. If the mutex is unlocked without + * a call to pthread_mutex_consistent(), it shall be in a permanently + * unusable state and all attempts to lock the mutex shall fail with + * the error [ENOTRECOVERABLE]. The only permissible operation on such + * a mutex is pthread_mutex_destroy(). + * + * RESULTS + * 0 successfully set attribute, + * EINVAL 'attr' or 'robust' is invalid, + * + * ------------------------------------------------------ + */ +{ + int result = EINVAL; + + if ((attr != NULL && *attr != NULL && robust != NULL)) + { + *robust = (*attr)->robustness; + result = 0; + } + + return (result); +} /* pthread_mutexattr_getrobust */ diff --git a/pthread_mutexattr_setrobust.c b/pthread_mutexattr_setrobust.c new file mode 100755 index 0000000..b1acef7 --- /dev/null +++ b/pthread_mutexattr_setrobust.c @@ -0,0 +1,119 @@ +/* + * pthread_mutexattr_setrobust.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutexattr_setrobust (pthread_mutexattr_t * attr, int robust) + /* + * ------------------------------------------------------ + * + * DOCPUBLIC + * The pthread_mutexattr_setrobust() and + * pthread_mutexattr_getrobust() functions respectively set and + * get the mutex robust attribute. This attribute is set in the + * robust parameter to these functions. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * robust + * must be one of: + * + * PTHREAD_MUTEX_STALLED + * + * PTHREAD_MUTEX_ROBUST + * + * DESCRIPTION + * The pthread_mutexattr_setrobust() and + * pthread_mutexattr_getrobust() functions respectively set and + * get the mutex robust attribute. This attribute is set in the + * robust parameter to these functions. The default value of the + * robust attribute is PTHREAD_MUTEX_STALLED. + * + * The robustness of mutex is contained in the robustness attribute + * of the mutex attributes. Valid mutex robustness values are: + * + * PTHREAD_MUTEX_STALLED + * No special actions are taken if the owner of the mutex is + * terminated while holding the mutex lock. This can lead to + * deadlocks if no other thread can unlock the mutex. + * This is the default value. + * + * PTHREAD_MUTEX_ROBUST + * If the process containing the owning thread of a robust mutex + * terminates while holding the mutex lock, the next thread that + * acquires the mutex shall be notified about the termination by + * the return value [EOWNERDEAD] from the locking function. If the + * owning thread of a robust mutex terminates while holding the mutex + * lock, the next thread that acquires the mutex may be notified + * about the termination by the return value [EOWNERDEAD]. The + * notified thread can then attempt to mark the state protected by + * the mutex as consistent again by a call to + * pthread_mutex_consistent(). After a subsequent successful call to + * pthread_mutex_unlock(), the mutex lock shall be released and can + * be used normally by other threads. If the mutex is unlocked without + * a call to pthread_mutex_consistent(), it shall be in a permanently + * unusable state and all attempts to lock the mutex shall fail with + * the error [ENOTRECOVERABLE]. The only permissible operation on such + * a mutex is pthread_mutex_destroy(). + * + * RESULTS + * 0 successfully set attribute, + * EINVAL 'attr' or 'robust' is invalid, + * + * ------------------------------------------------------ + */ +{ + int result = EINVAL; + + if ((attr != NULL && *attr != NULL)) + { + switch (robust) + { + case PTHREAD_MUTEX_STALLED: + case PTHREAD_MUTEX_ROBUST: + (*attr)->robustness = robust; + result = 0; + break; + } + } + + return (result); +} /* pthread_mutexattr_setrobust */ 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..65e0913 100644 --- a/pthread_win32_attach_detach_np.c +++ b/pthread_win32_attach_detach_np.c @@ -190,15 +190,35 @@ pthread_win32_thread_detach_np () if (sp != NULL) // otherwise Win32 thread with no implicit POSIX handle. { + ptw32_mcs_local_node_t stateLock; 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 + */ + while (sp->robustMxList != NULL) + { + pthread_mutex_t mx = sp->robustMxList->mx; + ptw32_robust_mutex_remove(&mx, sp); + (void) PTW32_INTERLOCKED_EXCHANGE( + (LPLONG)&mx->robustNode->stateInconsistent, + -1L); + /* + * 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); + } + 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..ac836ea 100644 --- a/ptw32_new.c +++ b/ptw32_new.c @@ -70,12 +70,15 @@ ptw32_new (void) } /* Set default state. */ + tp->seqNumber = ++ptw32_threadSeqNumber; tp->sched_priority = THREAD_PRIORITY_NORMAL; 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..830ae2e 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 &) { @@ -298,7 +301,7 @@ ptw32_threadStart (void *vthreadParms) /* * A system unexpected exception has occurred running the user's * terminate routine. We get control back within this block - * and exit with a substitue status. If the thread was not + * and exit with a substitute status. If the thread was not * cancelled then this indicates the unhandled exception. */ status = sp->exitStatus = PTHREAD_CANCELED; 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..bd8d7b7 100644 --- a/tests/Bmakefile +++ b/tests/Bmakefile @@ -85,13 +85,14 @@ PASSES= loadfree.pass \ mutex2r.pass mutex2e.pass mutex3r.pass mutex3e.pass \ condvar1.pass condvar1_1.pass condvar1_2.pass condvar2.pass condvar2_1.pass \ exit1.pass create1.pass create2.pass reuse1.pass reuse2.pass equal1.pass \ - kill1.pass valid1.pass valid2.pass \ + sequence1.pass kill1.pass valid1.pass valid2.pass \ exit2.pass exit3.pass exit4.pass exit5.pass \ join0.pass join1.pass detach1.pass join2.pass join3.pass \ mutex4.pass mutex6.pass mutex6n.pass mutex6e.pass mutex6r.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 \ @@ -318,6 +319,11 @@ priority1.pass: join1.pass priority2.pass: priority1.pass barrier3.pass reuse1.pass: create2.pass reuse2.pass: reuse1.pass +robust1.pass: mutex8r.pass +robust2.pass: mutex8r.pass +robust3.pass: robust2.pass +robust4.pass: robust3.pass +robust5.pass: robust4.pass rwlock1.pass: condvar6.pass rwlock2.pass: rwlock1.pass rwlock3.pass: rwlock2.pass @@ -340,6 +346,7 @@ semaphore3.pass: semaphore2.pass semaphore4.pass: semaphore3.pass cancel1.pass semaphore4t.pass: semaphore4.pass semaphore5.pass: semaphore4.pass +sequence1.pass: reuse2.pass sizes.pass: spin1.pass: spin2.pass: spin1.pass diff --git a/tests/ChangeLog b/tests/ChangeLog index 1ca1711..f5d8d08 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,29 @@ +2011-05-05 Ross Johnson + + * openmp1.c: Add missing test; used to comfirm that this + library works with libgomp; if this test produces a segfault + then try upgrading your version of libgomp/gcc; gcc version + 4.5.2 passes this test. + +2011-03-26 Ross Johnson + + * sequence1.c: New test for new pthread_getsequence_np(). + +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..9a46b2c 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. @@ -90,13 +92,14 @@ TESTS = \ semaphore1 semaphore2 semaphore3 \ condvar1 condvar1_1 condvar1_2 condvar2 condvar2_1 exit1 \ create1 create2 reuse1 reuse2 equal1 \ - kill1 valid1 valid2 \ + sequence1 kill1 valid1 valid2 \ exit2 exit3 exit4 exit5 \ join0 join1 detach1 join2 join3 \ mutex2 mutex2r mutex2e mutex3 mutex3r mutex3e \ 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 \ @@ -128,13 +131,14 @@ STATICTESTS = \ semaphore1 semaphore2 semaphore3 \ condvar1 condvar1_1 condvar1_2 condvar2 condvar2_1 exit1 \ create1 create2 reuse1 reuse2 equal1 \ - kill1 valid1 valid2 \ + sequence1 kill1 valid1 valid2 \ exit2 exit3 exit4 exit5 \ join0 join1 detach1 join2 join3 \ mutex2 mutex2r mutex2e mutex3 mutex3r mutex3e \ 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 @@ -330,6 +338,11 @@ priority1.pass: join1.pass priority2.pass: priority1.pass barrier3.pass reuse1.pass: create2.pass reuse2.pass: reuse1.pass +robust1.pass: mutex8r.pass +robust2.pass: mutex8r.pass +robust3.pass: robust2.pass +robust4.pass: robust3.pass +robust5.pass: robust4.pass rwlock1.pass: condvar6.pass rwlock2.pass: rwlock1.pass rwlock3.pass: rwlock2.pass @@ -352,6 +365,7 @@ semaphore3.pass: semaphore2.pass semaphore4.pass: semaphore3.pass cancel1.pass semaphore4t.pass: semaphore4.pass semaphore5.pass: semaphore4.pass +sequence1.pass: reuse2.pass sizes.pass: spin1.pass: spin2.pass: spin1.pass diff --git a/tests/Makefile b/tests/Makefile index 606f1d4..4164e1e 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -89,13 +89,14 @@ PASSES= sizes.pass loadfree.pass \ mutex2r.pass mutex2e.pass mutex3r.pass mutex3e.pass \ condvar1.pass condvar1_1.pass condvar1_2.pass condvar2.pass condvar2_1.pass \ exit1.pass create1.pass create2.pass reuse1.pass reuse2.pass equal1.pass \ - kill1.pass valid1.pass valid2.pass \ + sequence1.pass kill1.pass valid1.pass valid2.pass \ exit2.pass exit3.pass exit4.pass exit5.pass \ join0.pass join1.pass detach1.pass join2.pass join3.pass \ mutex4.pass mutex6.pass mutex6n.pass mutex6e.pass mutex6r.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 \ @@ -134,13 +135,14 @@ STATICRESULTS = \ mutex2r.pass mutex2e.pass mutex3r.pass mutex3e.pass \ condvar1.pass condvar1_1.pass condvar1_2.pass condvar2.pass condvar2_1.pass \ exit1.pass create1.pass create2.pass reuse1.pass reuse2.pass equal1.pass \ - kill1.pass valid1.pass valid2.pass \ + sequence1.pass kill1.pass valid1.pass valid2.pass \ exit2.pass exit3.pass exit4.pass exit5.pass \ join0.pass join1.pass detach1.pass join2.pass join3.pass \ mutex4.pass mutex6.pass mutex6n.pass mutex6e.pass mutex6r.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 \ @@ -406,6 +408,11 @@ priority1.pass: join1.pass priority2.pass: priority1.pass barrier3.pass reuse1.pass: create2.pass reuse2.pass: reuse1.pass +robust1.pass: mutex8r.pass +robust2.pass: mutex8r.pass +robust3.pass: robust2.pass +robust4.pass: robust3.pass +robust5.pass: robust4.pass rwlock1.pass: condvar6.pass rwlock2.pass: rwlock1.pass rwlock3.pass: rwlock2.pass @@ -428,6 +435,7 @@ semaphore3.pass: semaphore2.pass semaphore4.pass: semaphore3.pass cancel1.pass semaphore4t.pass: semaphore4.pass semaphore5.pass: semaphore4.pass +sequence1.pass: reuse2.pass sizes.pass: spin1.pass: spin2.pass: spin1.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/SIZES.VSE b/tests/SIZES.VSE index edc6427..709114d 100644 --- a/tests/SIZES.VSE +++ b/tests/SIZES.VSE @@ -1,19 +1,21 @@ -Sizes of pthreads-win32 structs -------------------------------- - pthread_t_ 68 - pthread_attr_t_ 28 - sem_t_ 4 - pthread_mutex_t_ 44 - pthread_mutexattr_t_ 8 - pthread_spinlock_t_ 8 - pthread_barrier_t_ 24 - pthread_barrierattr_t_ 4 - pthread_key_t_ 16 - pthread_cond_t_ 32 - pthread_condattr_t_ 4 - pthread_rwlock_t_ 28 - pthread_rwlockattr_t_ 4 - pthread_once_t_ 8 - ptw32_cleanup_t 12 - sched_param 4 -------------------------------- +Sizes of pthreads-win32 structs +------------------------------- + pthread_t 8 + ptw32_thread_t 96 + pthread_attr_t_ 28 + sem_t_ 12 + pthread_mutex_t_ 28 + pthread_mutexattr_t_ 12 + pthread_spinlock_t_ 8 + pthread_barrier_t_ 36 + pthread_barrierattr_t_ 4 + pthread_key_t_ 16 + pthread_cond_t_ 32 + pthread_condattr_t_ 4 + pthread_rwlock_t_ 28 + pthread_rwlockattr_t_ 4 + pthread_once_t_ 16 + ptw32_cleanup_t 12 + ptw32_mcs_node_t_ 16 + sched_param 4 +------------------------------- diff --git a/tests/Wmakefile b/tests/Wmakefile index fb988e3..0fcbd43 100644 --- a/tests/Wmakefile +++ b/tests/Wmakefile @@ -87,13 +87,14 @@ PASSES = sizes.pass loadfree.pass & mutex2r.pass mutex2e.pass mutex3r.pass mutex3e.pass & condvar1.pass condvar1_1.pass condvar1_2.pass condvar2.pass condvar2_1.pass & exit1.pass create1.pass create2.pass reuse1.pass reuse2.pass equal1.pass & - kill1.pass valid1.pass valid2.pass & + sequence1.pass kill1.pass valid1.pass valid2.pass & exit2.pass exit3.pass exit4 exit5 & join0.pass join1.pass detach1.pass join2.pass join3.pass & mutex4.pass mutex6.pass mutex6n.pass mutex6e.pass mutex6r.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 & @@ -316,6 +317,11 @@ priority1.pass: join1.pass priority2.pass: priority1.pass barrier3.pass reuse1.pass: create2.pass reuse2.pass: reuse1.pass +robust1.pass: mutex8r.pass +robust2.pass: mutex8r.pass +robust3.pass: robust2.pass +robust4.pass: robust3.pass +robust5.pass: robust4.pass rwlock1.pass: condvar6.pass rwlock2.pass: rwlock1.pass rwlock3.pass: rwlock2.pass @@ -337,6 +343,7 @@ semaphore3.pass: semaphore2.pass semaphore4.pass: semaphore3.pass cancel1.pass semaphore4t.pass: semaphore4.pass semaphore5.pass: semaphore4.pass +sequence1.pass: reuse2.pass sizes.pass: spin1.pass: spin2.pass: spin1.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/robust1.c b/tests/robust1.c new file mode 100755 index 0000000..100a854 --- /dev/null +++ b/tests/robust1.c @@ -0,0 +1,141 @@ +/* + * robust1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * For all robust mutex types. + * Thread A locks mutex + * Thread A terminates with no threads waiting on robust mutex + * Thread B acquires (inherits) mutex and unlocks + * Main attempts to lock mutex with unrecovered state. + * + * Depends on API functions: + * pthread_create() + * pthread_join() + * pthread_mutex_init() + * pthread_mutex_lock() + * pthread_mutex_unlock() + * pthread_mutex_destroy() + * pthread_mutexattr_init() + * pthread_mutexattr_setrobust() + * pthread_mutexattr_settype() + * pthread_mutexattr_destroy() + */ + +#include "test.h" + +static int lockCount; + +static pthread_mutex_t mutex; + +void * owner(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + + return 0; +} + +void * inheritor(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == EOWNERDEAD); + lockCount++; + assert(pthread_mutex_unlock(&mutex) == 0); + + return 0; +} + +int +main() +{ + pthread_t to, ti; + pthread_mutexattr_t ma; + + assert(pthread_mutexattr_init(&ma) == 0); + assert(pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST) == 0); + + /* Default (NORMAL) type */ + lockCount = 0; + assert(pthread_mutex_init(&mutex, &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_create(&ti, NULL, inheritor, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 2); + assert(pthread_mutex_lock(&mutex) == ENOTRECOVERABLE); + assert(pthread_mutex_unlock(&mutex) == EPERM); + assert(pthread_mutex_destroy(&mutex) == 0); + + /* NORMAL type */ + lockCount = 0; + assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_NORMAL) == 0); + assert(pthread_mutex_init(&mutex, &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_create(&ti, NULL, inheritor, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 2); + assert(pthread_mutex_lock(&mutex) == ENOTRECOVERABLE); + assert(pthread_mutex_unlock(&mutex) == EPERM); + assert(pthread_mutex_destroy(&mutex) == 0); + + /* ERRORCHECK type */ + lockCount = 0; + assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK) == 0); + assert(pthread_mutex_init(&mutex, &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_create(&ti, NULL, inheritor, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 2); + assert(pthread_mutex_lock(&mutex) == ENOTRECOVERABLE); + assert(pthread_mutex_unlock(&mutex) == EPERM); + assert(pthread_mutex_destroy(&mutex) == 0); + + /* RECURSIVE type */ + lockCount = 0; + assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE) == 0); + assert(pthread_mutex_init(&mutex, &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_create(&ti, NULL, inheritor, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 2); + assert(pthread_mutex_lock(&mutex) == ENOTRECOVERABLE); + assert(pthread_mutex_unlock(&mutex) == EPERM); + assert(pthread_mutex_destroy(&mutex) == 0); + + assert(pthread_mutexattr_destroy(&ma) == 0); + + return 0; +} diff --git a/tests/robust2.c b/tests/robust2.c new file mode 100755 index 0000000..2b3917a --- /dev/null +++ b/tests/robust2.c @@ -0,0 +1,143 @@ +/* + * robust2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * For all robust mutex types. + * Thread A locks mutex + * Thread B blocks on mutex + * Thread A terminates with threads waiting on robust mutex + * Thread B awakes and inherits mutex and unlocks + * Main attempts to lock mutex with unrecovered state. + * + * Depends on API functions: + * pthread_create() + * pthread_join() + * pthread_mutex_init() + * pthread_mutex_lock() + * pthread_mutex_unlock() + * pthread_mutex_destroy() + * pthread_mutexattr_init() + * pthread_mutexattr_setrobust() + * pthread_mutexattr_settype() + * pthread_mutexattr_destroy() + */ + +#include "test.h" + +static int lockCount; + +static pthread_mutex_t mutex; + +void * owner(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + Sleep(200); + + return 0; +} + +void * inheritor(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == EOWNERDEAD); + lockCount++; + assert(pthread_mutex_unlock(&mutex) == 0); + + return 0; +} + +int +main() +{ + pthread_t to, ti; + pthread_mutexattr_t ma; + + assert(pthread_mutexattr_init(&ma) == 0); + assert(pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST) == 0); + + /* Default (NORMAL) type */ + lockCount = 0; + assert(pthread_mutex_init(&mutex, &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + Sleep(100); + assert(pthread_create(&ti, NULL, inheritor, NULL) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 2); + assert(pthread_mutex_lock(&mutex) == ENOTRECOVERABLE); + assert(pthread_mutex_destroy(&mutex) == 0); + + /* NORMAL type */ + lockCount = 0; + assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_NORMAL) == 0); + assert(pthread_mutex_init(&mutex, &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + Sleep(100); + assert(pthread_create(&ti, NULL, inheritor, NULL) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 2); + assert(pthread_mutex_lock(&mutex) == ENOTRECOVERABLE); + assert(pthread_mutex_destroy(&mutex) == 0); + + /* ERRORCHECK type */ + lockCount = 0; + assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK) == 0); + assert(pthread_mutex_init(&mutex, &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + Sleep(100); + assert(pthread_create(&ti, NULL, inheritor, NULL) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 2); + assert(pthread_mutex_lock(&mutex) == ENOTRECOVERABLE); + assert(pthread_mutex_destroy(&mutex) == 0); + + /* RECURSIVE type */ + lockCount = 0; + assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE) == 0); + assert(pthread_mutex_init(&mutex, &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + Sleep(100); + assert(pthread_create(&ti, NULL, inheritor, NULL) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 2); + assert(pthread_mutex_lock(&mutex) == ENOTRECOVERABLE); + assert(pthread_mutex_destroy(&mutex) == 0); + + assert(pthread_mutexattr_destroy(&ma) == 0); + + return 0; +} diff --git a/tests/robust3.c b/tests/robust3.c new file mode 100755 index 0000000..cbf99df --- /dev/null +++ b/tests/robust3.c @@ -0,0 +1,149 @@ +/* + * robust3.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * For all robust mutex types. + * Thread A locks mutex + * Thread B blocks on mutex + * Thread A terminates with threads waiting on robust mutex + * Thread B awakes and inherits mutex, sets consistent and unlocks + * Main acquires mutex with recovered state. + * + * Depends on API functions: + * pthread_create() + * pthread_join() + * pthread_mutex_init() + * pthread_mutex_lock() + * pthread_mutex_unlock() + * pthread_mutex_consistent() + * pthread_mutex_destroy() + * pthread_mutexattr_init() + * pthread_mutexattr_setrobust() + * pthread_mutexattr_settype() + * pthread_mutexattr_destroy() + */ + +#include "test.h" + +static int lockCount; + +static pthread_mutex_t mutex; + +void * owner(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + Sleep(200); + + return 0; +} + +void * inheritor(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == EOWNERDEAD); + lockCount++; + assert(pthread_mutex_consistent(&mutex) == 0); + assert(pthread_mutex_unlock(&mutex) == 0); + + return 0; +} + +int +main() +{ + pthread_t to, ti; + pthread_mutexattr_t ma; + + assert(pthread_mutexattr_init(&ma) == 0); + assert(pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST) == 0); + + /* Default (NORMAL) type */ + lockCount = 0; + assert(pthread_mutex_init(&mutex, &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + Sleep(100); + assert(pthread_create(&ti, NULL, inheritor, NULL) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 2); + assert(pthread_mutex_lock(&mutex) == 0); + assert(pthread_mutex_unlock(&mutex) == 0); + assert(pthread_mutex_destroy(&mutex) == 0); + + /* NORMAL type */ + lockCount = 0; + assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_NORMAL) == 0); + assert(pthread_mutex_init(&mutex, &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + Sleep(100); + assert(pthread_create(&ti, NULL, inheritor, NULL) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 2); + assert(pthread_mutex_lock(&mutex) == 0); + assert(pthread_mutex_unlock(&mutex) == 0); + assert(pthread_mutex_destroy(&mutex) == 0); + + /* ERRORCHECK type */ + lockCount = 0; + assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK) == 0); + assert(pthread_mutex_init(&mutex, &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + Sleep(100); + assert(pthread_create(&ti, NULL, inheritor, NULL) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 2); + assert(pthread_mutex_lock(&mutex) == 0); + assert(pthread_mutex_unlock(&mutex) == 0); + assert(pthread_mutex_destroy(&mutex) == 0); + + /* RECURSIVE type */ + lockCount = 0; + assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE) == 0); + assert(pthread_mutex_init(&mutex, &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + Sleep(100); + assert(pthread_create(&ti, NULL, inheritor, NULL) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 2); + assert(pthread_mutex_lock(&mutex) == 0); + assert(pthread_mutex_unlock(&mutex) == 0); + assert(pthread_mutex_destroy(&mutex) == 0); + + assert(pthread_mutexattr_destroy(&ma) == 0); + + return 0; +} diff --git a/tests/robust4.c b/tests/robust4.c new file mode 100755 index 0000000..136a183 --- /dev/null +++ b/tests/robust4.c @@ -0,0 +1,199 @@ +/* + * robust4.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Thread A locks multiple robust mutexes + * Thread B blocks on same mutexes in different orderings + * Thread A terminates with thread waiting on mutexes + * Thread B awakes and inherits each mutex in turn, sets consistent and unlocks + * Main acquires mutexes with recovered state. + * + * Depends on API functions: + * pthread_create() + * pthread_join() + * pthread_mutex_init() + * pthread_mutex_lock() + * pthread_mutex_unlock() + * pthread_mutex_destroy() + * pthread_mutexattr_init() + * pthread_mutexattr_setrobust() + * pthread_mutexattr_settype() + * pthread_mutexattr_destroy() + */ + +#include "test.h" + +static int lockCount; + +static pthread_mutex_t mutex[3]; + +void * owner(void * arg) +{ + assert(pthread_mutex_lock(&mutex[0]) == 0); + lockCount++; + assert(pthread_mutex_lock(&mutex[1]) == 0); + lockCount++; + assert(pthread_mutex_lock(&mutex[2]) == 0); + lockCount++; + Sleep(200); + + return 0; +} + +void * inheritor(void * arg) +{ + int* o = (int*)arg; + + assert(pthread_mutex_lock(&mutex[o[0]]) == EOWNERDEAD); + lockCount++; + assert(pthread_mutex_lock(&mutex[o[1]]) == EOWNERDEAD); + lockCount++; + assert(pthread_mutex_lock(&mutex[o[2]]) == EOWNERDEAD); + lockCount++; + assert(pthread_mutex_consistent(&mutex[o[2]]) == 0); + assert(pthread_mutex_consistent(&mutex[o[1]]) == 0); + assert(pthread_mutex_consistent(&mutex[o[0]]) == 0); + assert(pthread_mutex_unlock(&mutex[o[2]]) == 0); + assert(pthread_mutex_unlock(&mutex[o[1]]) == 0); + assert(pthread_mutex_unlock(&mutex[o[0]]) == 0); + + return 0; +} + +int +main() +{ + pthread_t to, ti; + pthread_mutexattr_t ma; + int order[3]; + + assert(pthread_mutexattr_init(&ma) == 0); + assert(pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST) == 0); + + order[0]=0; + order[1]=1; + order[2]=2; + lockCount = 0; + assert(pthread_mutex_init(&mutex[0], &ma) == 0); + assert(pthread_mutex_init(&mutex[1], &ma) == 0); + assert(pthread_mutex_init(&mutex[2], &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + Sleep(100); + assert(pthread_create(&ti, NULL, inheritor, (void *)order) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 6); + assert(pthread_mutex_lock(&mutex[0]) == 0); + assert(pthread_mutex_unlock(&mutex[0]) == 0); + assert(pthread_mutex_destroy(&mutex[0]) == 0); + assert(pthread_mutex_lock(&mutex[1]) == 0); + assert(pthread_mutex_unlock(&mutex[1]) == 0); + assert(pthread_mutex_destroy(&mutex[1]) == 0); + assert(pthread_mutex_lock(&mutex[2]) == 0); + assert(pthread_mutex_unlock(&mutex[2]) == 0); + assert(pthread_mutex_destroy(&mutex[2]) == 0); + + order[0]=1; + order[1]=0; + order[2]=2; + lockCount = 0; + assert(pthread_mutex_init(&mutex[0], &ma) == 0); + assert(pthread_mutex_init(&mutex[1], &ma) == 0); + assert(pthread_mutex_init(&mutex[2], &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + Sleep(100); + assert(pthread_create(&ti, NULL, inheritor, (void *)order) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 6); + assert(pthread_mutex_lock(&mutex[0]) == 0); + assert(pthread_mutex_unlock(&mutex[0]) == 0); + assert(pthread_mutex_destroy(&mutex[0]) == 0); + assert(pthread_mutex_lock(&mutex[1]) == 0); + assert(pthread_mutex_unlock(&mutex[1]) == 0); + assert(pthread_mutex_destroy(&mutex[1]) == 0); + assert(pthread_mutex_lock(&mutex[2]) == 0); + assert(pthread_mutex_unlock(&mutex[2]) == 0); + assert(pthread_mutex_destroy(&mutex[2]) == 0); + + order[0]=0; + order[1]=2; + order[2]=1; + lockCount = 0; + assert(pthread_mutex_init(&mutex[0], &ma) == 0); + assert(pthread_mutex_init(&mutex[1], &ma) == 0); + assert(pthread_mutex_init(&mutex[2], &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + Sleep(100); + assert(pthread_create(&ti, NULL, inheritor, (void *)order) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 6); + assert(pthread_mutex_lock(&mutex[0]) == 0); + assert(pthread_mutex_unlock(&mutex[0]) == 0); + assert(pthread_mutex_destroy(&mutex[0]) == 0); + assert(pthread_mutex_lock(&mutex[1]) == 0); + assert(pthread_mutex_unlock(&mutex[1]) == 0); + assert(pthread_mutex_destroy(&mutex[1]) == 0); + assert(pthread_mutex_lock(&mutex[2]) == 0); + assert(pthread_mutex_unlock(&mutex[2]) == 0); + assert(pthread_mutex_destroy(&mutex[2]) == 0); + + order[0]=2; + order[1]=1; + order[2]=0; + lockCount = 0; + assert(pthread_mutex_init(&mutex[0], &ma) == 0); + assert(pthread_mutex_init(&mutex[1], &ma) == 0); + assert(pthread_mutex_init(&mutex[2], &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + Sleep(100); + assert(pthread_create(&ti, NULL, inheritor, (void *)order) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 6); + assert(pthread_mutex_lock(&mutex[0]) == 0); + assert(pthread_mutex_unlock(&mutex[0]) == 0); + assert(pthread_mutex_destroy(&mutex[0]) == 0); + assert(pthread_mutex_lock(&mutex[1]) == 0); + assert(pthread_mutex_unlock(&mutex[1]) == 0); + assert(pthread_mutex_destroy(&mutex[1]) == 0); + assert(pthread_mutex_lock(&mutex[2]) == 0); + assert(pthread_mutex_unlock(&mutex[2]) == 0); + assert(pthread_mutex_destroy(&mutex[2]) == 0); + + assert(pthread_mutexattr_destroy(&ma) == 0); + + return 0; +} diff --git a/tests/robust5.c b/tests/robust5.c new file mode 100755 index 0000000..c67d124 --- /dev/null +++ b/tests/robust5.c @@ -0,0 +1,120 @@ +/* + * robust5.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Thread A locks multiple robust mutexes + * Thread B blocks on same mutexes + * Thread A terminates with thread waiting on mutexes + * Thread B awakes and inherits each mutex in turn + * Thread B terminates leaving orphaned mutexes + * Main inherits mutexes, sets consistent and unlocks. + * + * Depends on API functions: + * pthread_create() + * pthread_join() + * pthread_mutex_init() + * pthread_mutex_lock() + * pthread_mutex_unlock() + * pthread_mutex_destroy() + * pthread_mutexattr_init() + * pthread_mutexattr_setrobust() + * pthread_mutexattr_settype() + * pthread_mutexattr_destroy() + */ + +#include "test.h" + +static int lockCount; + +static pthread_mutex_t mutex[3]; + +void * owner(void * arg) +{ + assert(pthread_mutex_lock(&mutex[0]) == 0); + lockCount++; + assert(pthread_mutex_lock(&mutex[1]) == 0); + lockCount++; + assert(pthread_mutex_lock(&mutex[2]) == 0); + lockCount++; + + return 0; +} + +void * inheritor(void * arg) +{ + assert(pthread_mutex_lock(&mutex[0]) == EOWNERDEAD); + lockCount++; + assert(pthread_mutex_lock(&mutex[1]) == EOWNERDEAD); + lockCount++; + assert(pthread_mutex_lock(&mutex[2]) == EOWNERDEAD); + lockCount++; + + return 0; +} + +int +main() +{ + pthread_t to, ti; + pthread_mutexattr_t ma; + + assert(pthread_mutexattr_init(&ma) == 0); + assert(pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST) == 0); + + lockCount = 0; + assert(pthread_mutex_init(&mutex[0], &ma) == 0); + assert(pthread_mutex_init(&mutex[1], &ma) == 0); + assert(pthread_mutex_init(&mutex[2], &ma) == 0); + assert(pthread_create(&to, NULL, owner, NULL) == 0); + assert(pthread_join(to, NULL) == 0); + assert(pthread_create(&ti, NULL, inheritor, NULL) == 0); + assert(pthread_join(ti, NULL) == 0); + assert(lockCount == 6); + assert(pthread_mutex_lock(&mutex[0]) == EOWNERDEAD); + assert(pthread_mutex_consistent(&mutex[0]) == 0); + assert(pthread_mutex_unlock(&mutex[0]) == 0); + assert(pthread_mutex_destroy(&mutex[0]) == 0); + assert(pthread_mutex_lock(&mutex[1]) == EOWNERDEAD); + assert(pthread_mutex_consistent(&mutex[1]) == 0); + assert(pthread_mutex_unlock(&mutex[1]) == 0); + assert(pthread_mutex_destroy(&mutex[1]) == 0); + assert(pthread_mutex_lock(&mutex[2]) == EOWNERDEAD); + assert(pthread_mutex_consistent(&mutex[2]) == 0); + assert(pthread_mutex_unlock(&mutex[2]) == 0); + assert(pthread_mutex_destroy(&mutex[2]) == 0); + + assert(pthread_mutexattr_destroy(&ma) == 0); + + return 0; +} diff --git a/tests/rwlock3.c b/tests/rwlock3.c index 4b22c5a..36ccf58 100644 --- a/tests/rwlock3.c +++ b/tests/rwlock3.c @@ -66,7 +66,7 @@ main() assert(pthread_create(&t, NULL, func, NULL) == 0); - Sleep(2000); + Sleep(20); assert(pthread_rwlock_unlock(&rwlock1) == 0); diff --git a/tests/rwlock4.c b/tests/rwlock4.c index edd9dc2..7ba6302 100644 --- a/tests/rwlock4.c +++ b/tests/rwlock4.c @@ -66,7 +66,7 @@ main() assert(pthread_create(&t, NULL, func, NULL) == 0); - Sleep(2000); + Sleep(20); assert(pthread_rwlock_unlock(&rwlock1) == 0); diff --git a/tests/rwlock5.c b/tests/rwlock5.c index 75b82f3..75880cd 100644 --- a/tests/rwlock5.c +++ b/tests/rwlock5.c @@ -68,7 +68,7 @@ main() assert(pthread_create(&t, NULL, func, NULL) == 0); - Sleep(2000); + Sleep(20); assert(pthread_rwlock_unlock(&rwlock1) == 0); diff --git a/tests/rwlock6.c b/tests/rwlock6.c index 0ac6b27..f667ce5 100644 --- a/tests/rwlock6.c +++ b/tests/rwlock6.c @@ -52,7 +52,7 @@ void * wrfunc(void * arg) int ba; assert(pthread_rwlock_wrlock(&rwlock1) == 0); - Sleep(2000); + Sleep(200); bankAccount += 10; ba = bankAccount; assert(pthread_rwlock_unlock(&rwlock1) == 0); @@ -84,9 +84,9 @@ main() bankAccount = 0; assert(pthread_create(&wrt1, NULL, wrfunc, NULL) == 0); - Sleep(500); + Sleep(50); assert(pthread_create(&rdt, NULL, rdfunc, NULL) == 0); - Sleep(500); + Sleep(50); assert(pthread_create(&wrt2, NULL, wrfunc, NULL) == 0); assert(pthread_join(wrt1, &wr1Result) == 0); diff --git a/tests/sequence1.c b/tests/sequence1.c new file mode 100755 index 0000000..e7d7db0 --- /dev/null +++ b/tests/sequence1.c @@ -0,0 +1,142 @@ +/* + * File: sequence1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - that unique thread sequence numbers are generated. + * - Analyse thread struct reuse. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - This test is implementation specific + * because it uses knowledge of internals that should be + * opaque to an application. + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - analysis output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - unique sequence numbers are generated for every new thread. + * + * Fail Criteria: + * - + */ + +#include "test.h" + +/* + */ + +enum { + NUMTHREADS = 10000 +}; + + +static long done = 0; +/* + * seqmap should have 1 in every element except [0] + * Thread sequence numbers start at 1 and we will also + * include this main thread so we need NUMTHREADS+2 + * elements. + */ +static UINT64 seqmap[NUMTHREADS+2]; + +void * func(void * arg) +{ + sched_yield(); + seqmap[(int)pthread_getunique_np(pthread_self())] = 1; + InterlockedIncrement(&done); + + return (void *) 0; +} + +int +main() +{ + pthread_t t[NUMTHREADS]; + pthread_attr_t attr; + int i; + + assert(pthread_attr_init(&attr) == 0); + assert(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0); + + for (i = 0; i <= NUMTHREADS+2; i++) + { + seqmap[i] = 0; + } + + for (i = 0; i < NUMTHREADS; i++) + { + if (NUMTHREADS/2 == i) + { + /* Include this main thread, which will be an implicit pthread_t */ + seqmap[(int)pthread_getunique_np(pthread_self())] = 1; + } + assert(pthread_create(&t[i], &attr, func, NULL) == 0); + } + + while (NUMTHREADS > InterlockedExchangeAdd((LPLONG)&done, 0L)) + Sleep(100); + + Sleep(100); + + assert(seqmap[0] == 0); + for (i = 1; i < NUMTHREADS+2; i++) + { + assert(seqmap[i] == 1); + } + + 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