diff options
90 files changed, 3165 insertions, 805 deletions
@@ -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 @@ -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 \ @@ -1,3 +1,19 @@ +2011-03-26 Ross Johnson <ross.johnson at homemail.com.au>
+
+ * 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 <ross.johnson at homemail.com.au>
+
+ * (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 <ross.johnson at homemail.com.au>
* 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 @@ -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 \ @@ -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
@@ -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; @@ -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 <ross at homemail dot com dot au> + + * 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 <ross at callisto.canberra.edu.au> - pthread_setschedparam.html: Fix "see also" links. + * pthread_setschedparam.html: Fix "see also" links. 2005-05-06 Ross Johnson <ross at callisto.canberra.edu.au> 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 @@ <HEAD> <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8"> <TITLE></TITLE> - <META NAME="GENERATOR" CONTENT="OpenOffice.org 1.1.3 (Linux)"> + <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.2 (Linux)"> <META NAME="CREATED" CONTENT="20050504;17350500"> - <META NAME="CHANGED" CONTENT="20050506;12240700"> + <META NAME="CHANGEDBY" CONTENT="Ross Johnson"> + <META NAME="CHANGED" CONTENT="20110326;18352700"> + <META NAME="CHANGEDBY" CONTENT="Ross Johnson"> + <STYLE TYPE="text/css"> + <!-- + H4.cjk { font-family: "AR PL UMing CN" } + H4.ctl { font-family: "Lohit Devanagari" } + H3.cjk { font-family: "AR PL UMing CN" } + H3.ctl { font-family: "Lohit Devanagari" } + H2.cjk { font-family: "AR PL UMing CN" } + H2.ctl { font-family: "Lohit Devanagari" } + --> + </STYLE> </HEAD> <BODY LANG="en-GB" DIR="LTR"> -<H4>POSIX Threads for Windows – REFERENCE - <A HREF="http://sources.redhat.com/pthreads-win32">Pthreads-w32</A></H4> -<H3>Table of Contents</H3> -<P STYLE="margin-left: 2cm"><A HREF="#sect1" NAME="toc1">POSIX +<H4 CLASS="western">POSIX Threads for Windows – REFERENCE - +<A HREF="http://sources.redhat.com/pthreads-win32">Pthreads-w32</A></H4> +<H3 CLASS="western">Table of Contents</H3> +<P STYLE="margin-left: 0.79in"><A HREF="#sect1" NAME="toc1">POSIX threads API reference</A><BR><A HREF="#sect2" NAME="toc2">Miscellaneous POSIX thread safe routines provided by Pthreads-w32</A><BR><A HREF="#sect3" NAME="toc3">Non-portable Pthreads-w32 routines</A><BR><A HREF="#sect4" NAME="toc4">Other</A></P> -<H2><A HREF="#toc1" NAME="sect1">POSIX threads API reference</A></H2> -<P STYLE="margin-left: 2cm"><A HREF="pthread_attr_init.html"><B>pthread_attr_destroy</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_attr_init.html"><B>pthread_attr_getdetachstate</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_attr_init.html"><B>pthread_attr_getinheritsched</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_attr_init.html"><B>pthread_attr_getschedparam</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_attr_init.html"><B>pthread_attr_getschedpolicy</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_attr_init.html"><B>pthread_attr_getscope</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_attr_setstackaddr.html"><B>pthread_attr_getstackaddr</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_attr_setstacksize.html"><B>pthread_attr_getstacksize</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_attr_init.html"><B>pthread_attr_init</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_attr_init.html"><B>pthread_attr_setdetachstate</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_attr_init.html"><B>pthread_attr_setinheritsched</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_attr_init.html"><B>pthread_attr_setschedparam</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_attr_init.html"><B>pthread_attr_setschedpolicy</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_attr_init.html"><B>pthread_attr_setscope</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_attr_setstackaddr.html"><B>pthread_attr_setstackaddr</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_attr_setstacksize.html"><B>pthread_attr_setstacksize</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_barrierattr_init.html"><B>pthread_barrierattr_destroy</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_barrierattr_setpshared.html"><B>pthread_barrierattr_getpshared</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_barrierattr_init.html"><B>pthread_barrierattr_init</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_barrierattr_setpshared.html"><B>pthread_barrierattr_setpshared</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_barrier_init.html"><B>pthread_barrier_destroy</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_barrier_init.html"><B>pthread_barrier_init</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_barrier_wait.html"><B>pthread_barrier_wait</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_cancel.html"><B>pthread_cancel</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_cleanup_push.html"><B>pthread_cleanup_pop</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_cleanup_push.html"><B>pthread_cleanup_push</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_condattr_init.html"><B>pthread_condattr_destroy</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_condattr_setpshared.html"><B>pthread_condattr_getpshared</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_condattr_init.html"><B>pthread_condattr_init</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_condattr_setpshared.html"><B>pthread_condattr_setpshared</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_cond_init.html"><B>pthread_cond_broadcast</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_cond_init.html"><B>pthread_cond_destroy</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_cond_init.html"><B>pthread_cond_init</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_cond_init.html"><B>pthread_cond_signal</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_cond_init.html"><B>pthread_cond_timedwait</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_cond_init.html"><B>pthread_cond_wait</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_create.html"><B>pthread_create</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_detach.html"><B>pthread_detach</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_equal.html"><B>pthread_equal</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_exit.html"><B>pthread_exit</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_setconcurrency.html"><B>pthread_getconcurrency</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_setschedparam.html"><B>pthread_getschedparam</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_key_create.html"><B>pthread_getspecific</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_join.html"><B>pthread_join</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_key_create.html"><B>pthread_key_create</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_key_create.html"><B>pthread_key_delete</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_kill.html"><B>pthread_kill</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_destroy</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_getkind_np</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_mutexattr_setpshared.html"><B>pthread_mutexattr_getpshared</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_gettype</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_init</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_setkind_np</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_mutexattr_setpshared.html"><B>pthread_mutexattr_setpshared</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_settype</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_mutex_init.html"><B>pthread_mutex_destroy</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_mutex_init.html"><B>pthread_mutex_init</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_mutex_init.html"><B>pthread_mutex_lock</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_mutex_init.html"><B>pthread_mutex_timedlock</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_mutex_init.html"><B>pthread_mutex_trylock</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_mutex_init.html"><B>pthread_mutex_unlock</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_once.html"><B>pthread_once</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_rwlockattr_init.html"><B>pthread_rwlockattr_destroy</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_rwlockattr_setpshared.html"><B>pthread_rwlockattr_getpshared</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_rwlockattr_init.html"><B>pthread_rwlockattr_init</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_rwlockattr_setpshared.html"><B>pthread_rwlockattr_setpshared</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_rwlock_init.html"><B>pthread_rwlock_destroy</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_rwlock_init.html"><B>pthread_rwlock_init</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_rwlock_rdlock.html"><B>pthread_rwlock_rdlock</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_rwlock_timedrdlock.html"><B>pthread_rwlock_timedrdlock</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_rwlock_timedwrlock.html"><B>pthread_rwlock_timedwrlock</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_rwlock_rdlock.html"><B>pthread_rwlock_tryrdlock</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_rwlock_wrlock.html"><B>pthread_rwlock_trywrlock</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_rwlock_unlock.html"><B>pthread_rwlock_unlock</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_rwlock_wrlock.html"><B>pthread_rwlock_wrlock</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_self.html"><B>pthread_self</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_cancel.html"><B>pthread_setcancelstate</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_cancel.html"><B>pthread_setcanceltype</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_setconcurrency.html"><B>pthread_setconcurrency</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_setschedparam.html"><B>pthread_setschedparam</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_key_create.html"><B>pthread_setspecific</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_kill.html"><B>pthread_sigmask</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_spin_init.html"><B>pthread_spin_destroy</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_spin_init.html"><B>pthread_spin_init</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_spin_lock.html"><B>pthread_spin_lock</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_spin_lock.html"><B>pthread_spin_trylock</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_spin_unlock.html"><B>pthread_spin_unlock</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_cancel.html"><B>pthread_testcancel</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="sched_get_priority_max.html"><B>sched_get_priority_max</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="sched_get_priority_max.html"><B>sched_get_priority_min</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="sched_getscheduler.html"><B>sched_getscheduler</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="sched_setscheduler.html"><B>sched_setscheduler</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="sched_yield.html"><B>sched_yield</B></A></P> -<P STYLE="margin-left: 2cm"><B>sem_close</B></P> -<P STYLE="margin-left: 2cm"><A HREF="sem_init.html"><B>sem_destroy</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="sem_init.html"><B>sem_getvalue</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="sem_init.html"><B>sem_init</B></A></P> -<P STYLE="margin-left: 2cm"><B>sem_open</B></P> -<P STYLE="margin-left: 2cm"><A HREF="sem_init.html"><B>sem_post</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="sem_init.html"><B>sem_post_multiple</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="sem_init.html"><B>sem_timedwait</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="sem_init.html"><B>sem_trywait</B></A></P> -<P STYLE="margin-left: 2cm"><B>sem_unlink</B></P> -<P STYLE="margin-left: 2cm"><A HREF="sem_init.html"><B>sem_wait</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_kill.html"><B>sigwait</B></A></P> -<H2><A HREF="#toc2" NAME="sect2">Miscellaneous POSIX thread safe -routines provided by Pthreads-w32</A></H2> -<P STYLE="margin-left: 2cm"><B>asctime_r</B></P> -<P STYLE="margin-left: 2cm"><B>ctime_r</B></P> -<P STYLE="margin-left: 2cm"><B>gmtime_r</B></P> -<P STYLE="margin-left: 2cm"><B>localtime_r</B></P> -<P STYLE="margin-left: 2cm"><B>rand_r</B></P> -<H2><A HREF="#toc3" NAME="sect3">Non-portable Pthreads-w32 routines</A></H2> -<P STYLE="margin-left: 2cm"><A HREF="pthreadCancelableWait.html"><B>pthreadCancelableTimedWait</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthreadCancelableWait.html"><B>pthreadCancelableWait</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_delay_np.html"><B>pthread_delay_np</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_getw32threadhandle_np.html"><B>pthread_getw32threadhandle_np</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_num_processors_np.html"><B>pthread_num_processors_np</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_win32_test_features_np.html"><B>pthread_win32_test_features_np</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_timechange_handler_np.html"><B>pthread_timechange_handler_np</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_win32_attach_detach_np.html"><B>pthread_win32_process_attach_np</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_win32_attach_detach_np.html"><B>pthread_win32_process_detach_np</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_win32_attach_detach_np.html"><B>pthread_win32_thread_attach_np</B></A></P> -<P STYLE="margin-left: 2cm"><A HREF="pthread_win32_attach_detach_np.html"><B>pthread_win32_thread_detach_np</B></A></P> -<H2><A HREF="#toc4" NAME="sect4">Other</A></H2> -<P STYLE="margin-left: 2cm"><A HREF="PortabilityIssues.html"><B>Portability +<H2 CLASS="western"><A HREF="#toc1" NAME="sect1">POSIX threads API +reference</A></H2> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_attr_init.html"><B>pthread_attr_destroy</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_attr_init.html"><B>pthread_attr_getdetachstate</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_attr_init.html"><B>pthread_attr_getinheritsched</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_attr_init.html"><B>pthread_attr_getschedparam</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_attr_init.html"><B>pthread_attr_getschedpolicy</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_attr_init.html"><B>pthread_attr_getscope</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_attr_setstackaddr.html"><B>pthread_attr_getstackaddr</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_attr_setstacksize.html"><B>pthread_attr_getstacksize</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_attr_init.html"><B>pthread_attr_init</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_attr_init.html"><B>pthread_attr_setdetachstate</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_attr_init.html"><B>pthread_attr_setinheritsched</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_attr_init.html"><B>pthread_attr_setschedparam</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_attr_init.html"><B>pthread_attr_setschedpolicy</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_attr_init.html"><B>pthread_attr_setscope</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_attr_setstackaddr.html"><B>pthread_attr_setstackaddr</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_attr_setstacksize.html"><B>pthread_attr_setstacksize</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_barrierattr_init.html"><B>pthread_barrierattr_destroy</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_barrierattr_setpshared.html"><B>pthread_barrierattr_getpshared</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_barrierattr_init.html"><B>pthread_barrierattr_init</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_barrierattr_setpshared.html"><B>pthread_barrierattr_setpshared</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_barrier_init.html"><B>pthread_barrier_destroy</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_barrier_init.html"><B>pthread_barrier_init</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_barrier_wait.html"><B>pthread_barrier_wait</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_cancel.html"><B>pthread_cancel</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_cleanup_push.html"><B>pthread_cleanup_pop</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_cleanup_push.html"><B>pthread_cleanup_push</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_condattr_init.html"><B>pthread_condattr_destroy</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_condattr_setpshared.html"><B>pthread_condattr_getpshared</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_condattr_init.html"><B>pthread_condattr_init</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_condattr_setpshared.html"><B>pthread_condattr_setpshared</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_cond_init.html"><B>pthread_cond_broadcast</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_cond_init.html"><B>pthread_cond_destroy</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_cond_init.html"><B>pthread_cond_init</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_cond_init.html"><B>pthread_cond_signal</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_cond_init.html"><B>pthread_cond_timedwait</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_cond_init.html"><B>pthread_cond_wait</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_create.html"><B>pthread_create</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_detach.html"><B>pthread_detach</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_equal.html"><B>pthread_equal</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_exit.html"><B>pthread_exit</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_setconcurrency.html"><B>pthread_getconcurrency</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_setschedparam.html"><B>pthread_getschedparam</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_getunique_np.html"><B>pthread_getunique_np</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_key_create.html"><B>pthread_getspecific</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_join.html"><B>pthread_join</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_key_create.html"><B>pthread_key_create</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_key_create.html"><B>pthread_key_delete</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_kill.html"><B>pthread_kill</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_destroy</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_getkind_np</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutexattr_setpshared.html"><B>pthread_mutexattr_getpshared</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_getrobust</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_gettype</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_init</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_setkind_np</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutexattr_setpshared.html"><B>pthread_mutexattr_setpshared</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_setrobust</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_settype</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutex_init.html"><B>pthread_mutex_consistent</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutex_init.html"><B>pthread_mutex_destroy</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutex_init.html"><B>pthread_mutex_init</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutex_init.html"><B>pthread_mutex_lock</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutex_init.html"><B>pthread_mutex_timedlock</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutex_init.html"><B>pthread_mutex_trylock</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_mutex_init.html"><B>pthread_mutex_unlock</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_once.html"><B>pthread_once</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_rwlockattr_init.html"><B>pthread_rwlockattr_destroy</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_rwlockattr_setpshared.html"><B>pthread_rwlockattr_getpshared</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_rwlockattr_init.html"><B>pthread_rwlockattr_init</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_rwlockattr_setpshared.html"><B>pthread_rwlockattr_setpshared</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_rwlock_init.html"><B>pthread_rwlock_destroy</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_rwlock_init.html"><B>pthread_rwlock_init</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_rwlock_rdlock.html"><B>pthread_rwlock_rdlock</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_rwlock_timedrdlock.html"><B>pthread_rwlock_timedrdlock</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_rwlock_timedwrlock.html"><B>pthread_rwlock_timedwrlock</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_rwlock_rdlock.html"><B>pthread_rwlock_tryrdlock</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_rwlock_wrlock.html"><B>pthread_rwlock_trywrlock</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_rwlock_unlock.html"><B>pthread_rwlock_unlock</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_rwlock_wrlock.html"><B>pthread_rwlock_wrlock</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_self.html"><B>pthread_self</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_cancel.html"><B>pthread_setcancelstate</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_cancel.html"><B>pthread_setcanceltype</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_setconcurrency.html"><B>pthread_setconcurrency</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_setschedparam.html"><B>pthread_setschedparam</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_key_create.html"><B>pthread_setspecific</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_kill.html"><B>pthread_sigmask</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_spin_init.html"><B>pthread_spin_destroy</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_spin_init.html"><B>pthread_spin_init</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_spin_lock.html"><B>pthread_spin_lock</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_spin_lock.html"><B>pthread_spin_trylock</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_spin_unlock.html"><B>pthread_spin_unlock</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_cancel.html"><B>pthread_testcancel</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="sched_get_priority_max.html"><B>sched_get_priority_max</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="sched_get_priority_max.html"><B>sched_get_priority_min</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="sched_getscheduler.html"><B>sched_getscheduler</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="sched_setscheduler.html"><B>sched_setscheduler</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="sched_yield.html"><B>sched_yield</B></A></P> +<P STYLE="margin-left: 0.79in"><B>sem_close</B></P> +<P STYLE="margin-left: 0.79in"><A HREF="sem_init.html"><B>sem_destroy</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="sem_init.html"><B>sem_getvalue</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="sem_init.html"><B>sem_init</B></A></P> +<P STYLE="margin-left: 0.79in"><B>sem_open</B></P> +<P STYLE="margin-left: 0.79in"><A HREF="sem_init.html"><B>sem_post</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="sem_init.html"><B>sem_post_multiple</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="sem_init.html"><B>sem_timedwait</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="sem_init.html"><B>sem_trywait</B></A></P> +<P STYLE="margin-left: 0.79in"><B>sem_unlink</B></P> +<P STYLE="margin-left: 0.79in"><A HREF="sem_init.html"><B>sem_wait</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_kill.html"><B>sigwait</B></A></P> +<H2 CLASS="western"><A HREF="#toc3" NAME="sect3">Non-portable +Pthreads-w32 routines</A></H2> +<P STYLE="margin-left: 0.79in"><A HREF="pthreadCancelableWait.html"><B>pthreadCancelableTimedWait</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthreadCancelableWait.html"><B>pthreadCancelableWait</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_delay_np.html"><B>pthread_delay_np</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_getw32threadhandle_np.html"><B>pthread_getw32threadhandle_np</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_num_processors_np.html"><B>pthread_num_processors_np</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_win32_test_features_np.html"><B>pthread_win32_test_features_np</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_timechange_handler_np.html"><B>pthread_timechange_handler_np</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_win32_attach_detach_np.html"><B>pthread_win32_process_attach_np</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_win32_attach_detach_np.html"><B>pthread_win32_process_detach_np</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_win32_attach_detach_np.html"><B>pthread_win32_thread_attach_np</B></A></P> +<P STYLE="margin-left: 0.79in"><A HREF="pthread_win32_attach_detach_np.html"><B>pthread_win32_thread_detach_np</B></A></P> +<H2 CLASS="western"><A HREF="#toc4" NAME="sect4">Other</A></H2> +<P STYLE="margin-left: 0.79in"><A HREF="PortabilityIssues.html"><B>Portability issues</B></A></P> </BODY> -</HTML> +</HTML>
\ 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 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> +<HEAD> + <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8"> + <TITLE>PTHREAD_GETW32THREADHANDLE_NP manual page</TITLE> + <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.2 (Linux)"> + <META NAME="CREATED" CONTENT="20050505;322600"> + <META NAME="CHANGEDBY" CONTENT="Ross Johnson"> + <META NAME="CHANGED" CONTENT="20110326;18290500"> + <META NAME="CHANGEDBY" CONTENT="Ross Johnson"> + <!-- manual page source format generated by PolyglotMan v3.2, --> + <!-- available at http://polyglotman.sourceforge.net/ --> + <STYLE TYPE="text/css"> + <!-- + H4.cjk { font-family: "AR PL UMing CN" } + H4.ctl { font-family: "Lohit Devanagari" } + H2.cjk { font-family: "AR PL UMing CN" } + H2.ctl { font-family: "Lohit Devanagari" } + --> + </STYLE> +</HEAD> +<BODY LANG="en-GB" BGCOLOR="#ffffff" DIR="LTR"> +<H4 CLASS="western">POSIX Threads for Windows – REFERENCE - +<A HREF="http://sources.redhat.com/pthreads-win32">Pthreads-w32</A></H4> +<P><A HREF="index.html">Reference Index</A></P> +<P><A HREF="#toc">Table of Contents</A></P> +<H2 CLASS="western"><A HREF="#toc0" NAME="sect0">Name</A></H2> +<P STYLE="font-weight: normal">pthread_getunique_np – get the +unique sequence number associated with a thread</P> +<H2 CLASS="western"><A HREF="#toc1" NAME="sect1">Synopsis</A></H2> +<P><B>#include <pthread.h></B> +</P> +<P><B>unsigned long long pthread_getunique_np(pthread_t</B> <I>thread</I><B>);</B></P> +<H2 CLASS="western"><A HREF="#toc2" NAME="sect2">Description</A></H2> +<P>Returns the <B>unique </B><SPAN STYLE="font-weight: normal">64 bit +sequence number</SPAN> assigned to <I>thread</I>.</P> +<P>In <B>Pthreads-win32:</B></P> +<UL> + <LI><P>the value returned is not reused after the thread terminates + so it is unique for the life of the process</P> + <LI><P>Windows native threads may obtain their own POSIX thread + sequence number by first retrieving their <B>pthread_t</B> handle + via <B>pthread_self</B> to use as the <I>thread</I> argument.</P> +</UL> +<P>This function was added for source code compatibility with some +other POSIX threads implementations.</P> +<H2 CLASS="western"><A HREF="#toc3" NAME="sect3">Cancellation</A></H2> +<P>None.</P> +<H2 CLASS="western"><A HREF="#toc4" NAME="sect4">Return Value</A></H2> +<P><B>pthread_getunique_np</B> returns the unique sequence number for +<I>thread</I>.</P> +<H2 CLASS="western"><A HREF="#toc5" NAME="sect5">Errors</A></H2> +<P>None.</P> +<H2 CLASS="western"><A HREF="#toc6" NAME="sect6">Author</A></H2> +<P>Ross Johnson for use with <A HREF="http://sources.redhat.com/pthreads-win32">Pthreads-w32</A>.</P> +<HR> +<P><A NAME="toc"></A><B>Table of Contents</B></P> +<UL> + <LI><P STYLE="margin-bottom: 0in"><A HREF="#sect0" NAME="toc0">Name</A> + </P> + <LI><P STYLE="margin-bottom: 0in"><A HREF="#sect1" NAME="toc1">Synopsis</A> + </P> + <LI><P STYLE="margin-bottom: 0in"><A HREF="#sect2" NAME="toc2">Description</A> + </P> + <LI><P STYLE="margin-bottom: 0in"><A HREF="#sect3" NAME="toc3">Cancellation</A> + </P> + <LI><P STYLE="margin-bottom: 0in"><A HREF="#sect4" NAME="toc4">Return + Value</A> + </P> + <LI><P STYLE="margin-bottom: 0in"><A HREF="#sect5" NAME="toc5">Errors</A> + </P> + <LI><P><A HREF="#sect6" NAME="toc6">Author</A> + </P> +</UL> +</BODY> +</HTML>
\ 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 @@ <HEAD> <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8"> <TITLE>PTHREAD_MUTEX(3) manual page</TITLE> - <META NAME="GENERATOR" CONTENT="OpenOffice.org 1.1.3 (Linux)"> + <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.2 (Linux)"> <META NAME="CREATED" CONTENT="20050505;5000"> - <META NAME="CHANGED" CONTENT="20050505;19000600"> + <META NAME="CHANGEDBY" CONTENT="Ross Johnson"> + <META NAME="CHANGED" CONTENT="20110326;15072100"> + <META NAME="CHANGEDBY" CONTENT="Ross Johnson"> + <META NAME="CHANGEDBY" CONTENT="Ross Johnson"> <!-- manual page source format generated by PolyglotMan v3.2, --> <!-- available at http://polyglotman.sourceforge.net/ --> + <STYLE TYPE="text/css"> + <!-- + H4.cjk { font-family: "AR PL UMing CN" } + H4.ctl { font-family: "Lohit Devanagari" } + H2.cjk { font-family: "AR PL UMing CN" } + H2.ctl { font-family: "Lohit Devanagari" } + PRE.cjk { font-family: "AR PL UMing CN", monospace } + PRE.ctl { font-family: "Lohit Devanagari", monospace } + --> + </STYLE> </HEAD> <BODY LANG="en-GB" BGCOLOR="#ffffff" DIR="LTR"> -<H4>POSIX Threads for Windows – REFERENCE - <A HREF="http://sources.redhat.com/pthreads-win32">Pthreads-w32</A></H4> +<H4 CLASS="western">POSIX Threads for Windows – REFERENCE - +<A HREF="http://sources.redhat.com/pthreads-win32">Pthreads-w32</A></H4> <P><A HREF="index.html">Reference Index</A></P> <P><A HREF="#toc">Table of Contents</A></P> -<H2><A HREF="#toc0" NAME="sect0">Name</A></H2> +<H2 CLASS="western"><A HREF="#toc0" NAME="sect0">Name</A></H2> <P>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 </P> -<H2><A HREF="#toc1" NAME="sect1">Synopsis</A></H2> +<H2 CLASS="western"><A HREF="#toc1" NAME="sect1">Synopsis</A></H2> <P><B>#include <pthread.h></B> </P> <P><B>#include <time.h></B></P> @@ -49,9 +64,11 @@ const pthread_mutexattr_t *</B><I>mutexattr</I><B>);</B> </P> <P><B>int pthread_mutex_unlock(pthread_mutex_t *</B><I>mutex</I><B>);</B> </P> +<P><B>int pthread_mutex_consistent(pthread_mutex_t *</B><I>mutex</I><B>);</B> +</P> <P><B>int pthread_mutex_destroy(pthread_mutex_t *</B><I>mutex</I><B>);</B> </P> -<H2><A HREF="#toc2" NAME="sect2">Description</A></H2> +<H2 CLASS="western"><A HREF="#toc2" NAME="sect2">Description</A></H2> <P>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 <B>PTHREAD_MUTEX_INITIALIZER</B> (for normal “fast” mutexes), <B>PTHREAD_RECURSIVE_MUTEX_INITIALIZER</B> (for recursive mutexes), and <B>PTHREAD_ERRORCHECK_MUTEX_INITIALIZER</B> -(for error checking mutexes). <SPAN STYLE="font-weight: medium"> In -the <B>Pthreads-w32</B> implementation, an application should still -call <B>pthread_mutex_destroy</B> at some point to ensure that any +(for error checking mutexes). <SPAN STYLE="font-weight: normal">In +the </SPAN><B>Pthreads-w32</B> <SPAN STYLE="font-weight: normal">implementation, +an application should still call </SPAN><B>pthread_mutex_destroy</B> +<SPAN STYLE="font-weight: normal">at some point to ensure that any resources consumed by the mutex are released.</SPAN></P> +<P><SPAN STYLE="font-weight: normal">Any mutex type can be +initialized as a </SPAN><B>robust mutex</B><SPAN STYLE="font-weight: normal">. +See </SPAN><A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_init</B><SPAN STYLE="font-weight: normal">(3)</SPAN></A> +<SPAN STYLE="font-weight: normal">for more information as well as the +section </SPAN><I><U><SPAN STYLE="font-weight: normal">Robust Mutexes</SPAN></U></I> +<SPAN STYLE="font-weight: normal">below.</SPAN></P> <P><B>pthread_mutex_lock</B> locks the given mutex. If the mutex is currently unlocked, it becomes locked and owned by the calling thread, and <B>pthread_mutex_lock</B> returns immediately. If the mutex is already locked by another thread, <B>pthread_mutex_lock</B> -suspends the calling thread until the mutex is unlocked. -</P> +suspends the calling thread until the mutex is unlocked.</P> <P>If the mutex is already locked by the calling thread, the behavior of <B>pthread_mutex_lock</B> 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. <P><B>pthread_mutex_trylock</B> behaves identically to <B>pthread_mutex_lock</B>, 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, -<B>pthread_mutex_trylock</B> returns immediately with the error code -<B>EBUSY</B>. +calling thread in the case of a “normal” or “<SPAN STYLE="font-style: normal">errorcheck</SPAN>” +mutex). Instead, <B>pthread_mutex_trylock</B> returns immediately +with the error code <B>EBUSY</B>. </P> <P><B>pthread_mutex_timedlock</B> behaves identically to <B>pthread_mutex_lock</B>, except that if it cannot acquire the lock before the <I>abs_timeout</I> time, the call returns with the error code <B>ETIMEDOUT</B>. If the mutex can be locked immediately it is, and the <B>abs_timeout</B> parameter is ignored.</P> +<P><B>pthread_mutex_consistent</B> may only be called for +<B>PTHREAD_MUTEX_ROBUST</B> mutexes. It simply marks the mutex as +consistent. See <I><U>Robust Mutexes</U></I> below.</P> <P><B>pthread_mutex_unlock</B> unlocks the given mutex. The mutex is assumed to be locked and owned by the calling thread on entrance to <B>pthread_mutex_unlock</B>. If the mutex is of the “normal” @@ -117,19 +143,53 @@ type, <B>pthread_mutex_unlock</B> always returns it to the unlocked state. If it is of the ‘‘recursive’’ type, it decrements the locking count of the mutex (number of <B>pthread_mutex_lock</B> operations performed on it by the calling thread), and only when this -count reaches zero is the mutex actually unlocked. -</P> +count reaches zero is the mutex actually unlocked. In <B>Pthreads-win32</B>, +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.</P> <P>On ‘‘error checking’’ mutexes, <B>pthread_mutex_unlock</B> 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 <B>pthread_mutex_unlock</B>. 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.</P> +[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.</P> <P><B>pthread_mutex_destroy</B> destroys a mutex object, freeing the resources it might hold. The mutex must be unlocked on entrance.</P> -<H2><A HREF="#toc3" NAME="sect3">Cancellation</A></H2> +<H2 CLASS="western"><A HREF="#toc10" NAME="sect10">Robust Mutexes</A></H2> +<P>If the mutex is <B>PTHREAD_MUTEX_ROBUST</B> 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 <B>EOWNERDEAD</B><SPAN STYLE="font-weight: normal">, +in which case that thread should if possible ensure that the state +protected by the mutex is consistent and then call +</SPAN><B>pthread_mutex_consistent</B> <SPAN STYLE="font-weight: normal">before +unlocking. The mutex may then be used normally from then on.</SPAN></P> +<P><SPAN STYLE="font-weight: normal">If the thread cannot recover the +state then it must call </SPAN><B>pthread_mutex_unlock</B><SPAN STYLE="font-weight: normal"> +without calling </SPAN><B>pthread_mutex_consistent</B><SPAN STYLE="font-weight: normal">. +This will mark the mutex as unusable and wake all currently waiting +threads with the return code </SPAN><B>ENOTRECOVERABLE</B><SPAN STYLE="font-weight: normal">. +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 +</SPAN><B>pthread_mutex_destroy</B> <SPAN STYLE="font-weight: normal">to +uninitialize the mutex, and calling </SPAN><B>pthread_mutex_int</B> +<SPAN STYLE="font-weight: normal">to reinitialize the mutex. However, +the state that was protected by the mutex remains inconsistent and +some form of application recovery is required.</SPAN></P> +<P><SPAN STYLE="font-weight: normal">If a thread that receives the +</SPAN><B>EOWNERDEAD</B> <SPAN STYLE="font-weight: normal">error code +itself terminates without unlocking the mutex then this behaviour +repeats for the next acquiring thread.</SPAN></P> +<P><SPAN STYLE="font-weight: normal">Applications must ensure that +they check the return values from all calls targeting robust mutexes.</SPAN></P> +<P STYLE="font-weight: normal">Robust mutexes are slower because they +require some additional overhead, however they are not very much +slower than the non-robust recursive type.</P> +<H2 CLASS="western"><A HREF="#toc3" NAME="sect3">Cancellation</A></H2> <P>None of the mutex functions is a cancellation point, not even <B>pthread_mutex_lock</B>, 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. </P> -<H2><A HREF="#toc4" NAME="sect4">Async-signal Safety</A></H2> +<H2 CLASS="western"><A HREF="#toc4" NAME="sect4">Async-signal Safety</A></H2> <P>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 <B>pthread_mutex_lock</B> or <B>pthread_mutex_unlock</B> from a signal handler may deadlock the calling thread. </P> -<H2><A HREF="#toc5" NAME="sect5">Return Value</A></H2> +<H2 CLASS="western"><A HREF="#toc5" NAME="sect5">Return Value</A></H2> <P><B>pthread_mutex_init</B> always returns 0. The other mutex functions return 0 on success and a non-zero error code on error. </P> -<H2><A HREF="#toc6" NAME="sect6">Errors</A></H2> +<H2 CLASS="western"><A HREF="#toc6" NAME="sect6">Errors</A></H2> <P>The <B>pthread_mutex_lock</B> function returns the following error code on error: </P> <DL> <DL> - <DT STYLE="margin-right: 1cm; margin-bottom: 0.5cm"><B>EINVAL</B> - </DT><DD STYLE="margin-right: 1cm; margin-bottom: 0.5cm"> + <DT STYLE="margin-right: 0.39in; margin-bottom: 0.2in"><B>EINVAL</B></DT><DD STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> the mutex has not been properly initialized. - </DD><DT STYLE="margin-right: 1cm; margin-bottom: 0.5cm"> - <B>EDEADLK</B> - </DT><DD STYLE="margin-right: 1cm; margin-bottom: 0.5cm"> + </DD><DT STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> + <B>EDEADLK</B></DT><DD STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> the mutex is already locked by the calling thread (‘‘error checking’’ mutexes only). - </DD></DL> -</DL> -<P> -The <B>pthread_mutex_trylock</B> function returns the following error -codes on error: -</P> -<DL> - <DL> - <DT STYLE="margin-right: 1cm; margin-bottom: 0.5cm"><B>EBUSY</B> - </DT><DD STYLE="margin-right: 1cm; margin-bottom: 0.5cm"> + </DD><DT STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> + <B>EOWNERDEAD</B></DT><DD STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> + the robust mutex is now locked by the calling thread after the + previous owner terminated without unlocking it.</DD><DT STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> + <B>ENOTRECOVERABLE</B></DT><DD STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> + the robust mutex is not locked and is no longer usable after the + previous owner unlocked it without calling + pthread_mutex_consistent.</DD></DL> + <DD STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> + The <B>pthread_mutex_trylock</B> function returns the following + error codes on error: + </DD><DL> + <DT STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> + <B>EBUSY</B> + </DT><DD STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> the mutex could not be acquired because it was currently locked. - </DD><DT STYLE="margin-right: 1cm; margin-bottom: 0.5cm"> + </DD><DT STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> <B>EINVAL</B> - </DT><DD STYLE="margin-right: 1cm; margin-bottom: 0.5cm"> + </DT><DD STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> the mutex has not been properly initialized. - </DD></DL> + </DD><DT STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> + <B>EOWNERDEAD</B></DT><DD STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> + the robust mutex is now locked by the calling thread after the + previous owner terminated without unlocking it.</DD><DT STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> + <B>ENOTRECOVERABLE</B></DT><DD STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> + the robust mutex is not locked and is no longer usable after the + previous owner unlocked it without calling + pthread_mutex_consistent.</DD></DL> </DL> <P> The <B>pthread_mutex_timedlock</B> function returns the following @@ -185,15 +255,22 @@ error codes on error: </P> <DL> <DL> - <DT STYLE="margin-right: 1cm; margin-bottom: 0.5cm"><B>ETIMEDOUT</B> - </DT><DD STYLE="margin-right: 1cm; margin-bottom: 0.5cm"> + <DT STYLE="margin-right: 0.39in; margin-bottom: 0.2in"><B>ETIMEDOUT</B> + </DT><DD STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> the mutex could not be acquired before the <I>abs_timeout</I> time arrived. - </DD><DT STYLE="margin-right: 1cm; margin-bottom: 0.5cm"> + </DD><DT STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> <B>EINVAL</B> - </DT><DD STYLE="margin-right: 1cm; margin-bottom: 0.5cm"> + </DT><DD STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> the mutex has not been properly initialized. - </DD></DL> + </DD><DT STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> + <B>EOWNERDEAD</B></DT><DD STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> + the robust mutex is now locked by the calling thread after the + previous owner terminated without unlocking it.</DD><DT STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> + <B>ENOTRECOVERABLE</B></DT><DD STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> + the robust mutex is not locked and is no longer usable after the + previous owner unlocked it without calling + pthread_mutex_consistent.</DD></DL> </DL> <P> The <B>pthread_mutex_unlock</B> function returns the following error @@ -201,12 +278,12 @@ code on error: </P> <DL> <DL> - <DT STYLE="margin-right: 1cm; margin-bottom: 0.5cm"><B>EINVAL</B> - </DT><DD STYLE="margin-right: 1cm; margin-bottom: 0.5cm"> + <DT STYLE="margin-right: 0.39in; margin-bottom: 0.2in"><B>EINVAL</B> + </DT><DD STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> the mutex has not been properly initialized. - </DD><DT STYLE="margin-right: 1cm; margin-bottom: 0.5cm"> + </DD><DT STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> <B>EPERM</B> - </DT><DD STYLE="margin-right: 1cm; margin-bottom: 0.5cm"> + </DT><DD STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> the calling thread does not own the mutex (‘‘error checking’’ mutexes only). </DD></DL> @@ -217,61 +294,63 @@ code on error: </P> <DL> <DL> - <DT STYLE="margin-right: 1cm; margin-bottom: 0.5cm"><B>EBUSY</B> - </DT><DD STYLE="margin-right: 1cm; margin-bottom: 0.5cm"> + <DT STYLE="margin-right: 0.39in; margin-bottom: 0.2in"><B>EBUSY</B> + </DT><DD STYLE="margin-right: 0.39in; margin-bottom: 0.2in"> the mutex is currently locked. </DD></DL> </DL> -<H2> +<H2 CLASS="western"> <A HREF="#toc7" NAME="sect7">Author</A></H2> <P>Xavier Leroy <Xavier.Leroy@inria.fr> </P> <P>Modified by Ross Johnson for use with <A HREF="http://sources.redhat.com/pthreads-win32">Pthreads-w32</A>.</P> -<H2><A HREF="#toc8" NAME="sect8">See Also</A></H2> +<H2 CLASS="western"><A HREF="#toc8" NAME="sect8">See Also</A></H2> <P><A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_init</B>(3)</A> , <A HREF="pthread_mutexattr_init.html"><B>pthread_mutexattr_settype</B>(3)</A> , <A HREF="pthread_cancel.html"><B>pthread_cancel</B>(3)</A> . </P> -<H2><A HREF="#toc9" NAME="sect9">Example</A></H2> +<H2 CLASS="western"><A HREF="#toc9" NAME="sect9">Example</A></H2> <P>A shared global variable <I>x</I> can be protected by a mutex as follows: </P> -<PRE STYLE="margin-left: 1cm; margin-right: 1cm">int x; -pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;</PRE><BLOCKQUOTE STYLE="margin-left: 0cm; margin-right: 0cm"> +<PRE CLASS="western" STYLE="margin-left: 0.39in; margin-right: 0.39in">int x; +pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;</PRE><BLOCKQUOTE STYLE="margin-left: 0in; margin-right: 0in"> All accesses and modifications to <I>x</I> should be bracketed by calls to <B>pthread_mutex_lock</B> and <B>pthread_mutex_unlock</B> as follows: </BLOCKQUOTE> -<PRE STYLE="margin-left: 1.03cm; margin-right: 2cm">pthread_mutex_lock(&mut); +<PRE CLASS="western" STYLE="margin-left: 0.41in; margin-right: 0.79in">pthread_mutex_lock(&mut); /* operate on x */ pthread_mutex_unlock(&mut);</PRE> <HR> -<BLOCKQUOTE STYLE="margin-right: 4cm"><A NAME="toc"></A><B>Table of -Contents</B></BLOCKQUOTE> +<BLOCKQUOTE STYLE="margin-right: 2.75in"><A NAME="toc"></A><B>Table +of Contents</B></BLOCKQUOTE> <UL> - <LI><BLOCKQUOTE STYLE="margin-right: 4cm; margin-bottom: 0cm"><A HREF="#sect0" NAME="toc0">Name</A> + <LI><BLOCKQUOTE STYLE="margin-right: 2.75in; margin-bottom: 0in"><A HREF="#sect0" NAME="toc0">Name</A> </BLOCKQUOTE> - <LI><BLOCKQUOTE STYLE="margin-right: 4cm; margin-bottom: 0cm"><A HREF="#sect1" NAME="toc1">Synopsis</A> + <LI><BLOCKQUOTE STYLE="margin-right: 2.75in; margin-bottom: 0in"><A HREF="#sect1" NAME="toc1">Synopsis</A> </BLOCKQUOTE> - <LI><BLOCKQUOTE STYLE="margin-right: 4cm; margin-bottom: 0cm"><A HREF="#sect2" NAME="toc2">Description</A> + <LI><BLOCKQUOTE STYLE="margin-right: 2.75in; margin-bottom: 0in"><A HREF="#sect2" NAME="toc2">Description</A> </BLOCKQUOTE> - <LI><BLOCKQUOTE STYLE="margin-right: 4cm; margin-bottom: 0cm"><A HREF="#sect3" NAME="toc3">Cancellation</A> + <LI><BLOCKQUOTE STYLE="margin-right: 2.75in; margin-bottom: 0in"><A HREF="#sect10" NAME="toc10">Robust + Mutexes</A></BLOCKQUOTE> + <LI><BLOCKQUOTE STYLE="margin-right: 2.75in; margin-bottom: 0in"><A HREF="#sect3" NAME="toc3">Cancellation</A> </BLOCKQUOTE> - <LI><BLOCKQUOTE STYLE="margin-right: 4cm; margin-bottom: 0cm"><A HREF="#sect4" NAME="toc4">Async-signal + <LI><BLOCKQUOTE STYLE="margin-right: 2.75in; margin-bottom: 0in"><A HREF="#sect4" NAME="toc4">Async-signal Safety</A> </BLOCKQUOTE> - <LI><BLOCKQUOTE STYLE="margin-right: 4cm; margin-bottom: 0cm"><A HREF="#sect5" NAME="toc5">Return + <LI><BLOCKQUOTE STYLE="margin-right: 2.75in; margin-bottom: 0in"><A HREF="#sect5" NAME="toc5">Return Value</A> </BLOCKQUOTE> - <LI><BLOCKQUOTE STYLE="margin-right: 4cm; margin-bottom: 0cm"><A HREF="#sect6" NAME="toc6">Errors</A> + <LI><BLOCKQUOTE STYLE="margin-right: 2.75in; margin-bottom: 0in"><A HREF="#sect6" NAME="toc6">Errors</A> </BLOCKQUOTE> - <LI><BLOCKQUOTE STYLE="margin-right: 4cm; margin-bottom: 0cm"><A HREF="#sect7" NAME="toc7">Author</A> + <LI><BLOCKQUOTE STYLE="margin-right: 2.75in; margin-bottom: 0in"><A HREF="#sect7" NAME="toc7">Author</A> </BLOCKQUOTE> - <LI><BLOCKQUOTE STYLE="margin-right: 4cm; margin-bottom: 0cm"><A HREF="#sect8" NAME="toc8">See + <LI><BLOCKQUOTE STYLE="margin-right: 2.75in; margin-bottom: 0in"><A HREF="#sect8" NAME="toc8">See Also</A> </BLOCKQUOTE> - <LI><BLOCKQUOTE STYLE="margin-right: 4cm"><A HREF="#sect9" NAME="toc9">Example</A> + <LI><BLOCKQUOTE STYLE="margin-right: 2.75in"><A HREF="#sect9" NAME="toc9">Example</A> </BLOCKQUOTE> </UL> </BODY> -</HTML> +</HTML>
\ 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 @@ <HEAD> <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8"> <TITLE>PTHREAD_MUTEXATTR(3) manual page</TITLE> - <META NAME="GENERATOR" CONTENT="OpenOffice.org 1.1.3 (Linux)"> + <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.2 (Linux)"> <META NAME="CREATED" CONTENT="20050504;23040500"> - <META NAME="CHANGED" CONTENT="20050505;18370400"> + <META NAME="CHANGEDBY" CONTENT="Ross Johnson"> + <META NAME="CHANGED" CONTENT="20110326;13190500"> <!-- manual page source format generated by PolyglotMan v3.2, --> <!-- available at http://polyglotman.sourceforge.net/ --> + <STYLE TYPE="text/css"> + <!-- + H4.cjk { font-family: "AR PL UMing CN" } + H4.ctl { font-family: "Lohit Devanagari" } + H2.cjk { font-family: "AR PL UMing CN" } + H2.ctl { font-family: "Lohit Devanagari" } + --> + </STYLE> </HEAD> <BODY LANG="en-GB" BGCOLOR="#ffffff" DIR="LTR"> -<H4>POSIX Threads for Windows – REFERENCE - <A HREF="http://sources.redhat.com/pthreads-win32">Pthreads-w32</A></H4> +<H4 CLASS="western">POSIX Threads for Windows – REFERENCE - +<A HREF="http://sources.redhat.com/pthreads-win32">Pthreads-w32</A></H4> <P><A HREF="index.html">Reference Index</A></P> <P><A HREF="#toc">Table of Contents</A></P> -<H2><A HREF="#toc0" NAME="sect0">Name</A></H2> +<H2 CLASS="western"><A HREF="#toc0" NAME="sect0">Name</A></H2> <P>pthread_mutexattr_init, pthread_mutexattr_destroy, pthread_mutexattr_settype, pthread_mutexattr_gettype - mutex creation attributes </P> -<H2><A HREF="#toc1" NAME="sect1">Synopsis</A></H2> +<H2 CLASS="western"><A HREF="#toc1" NAME="sect1">Synopsis</A></H2> <P><B>#include <pthread.h></B> </P> <P><B>int pthread_mutexattr_init(pthread_mutexattr_t *</B><I>attr</I><B>);</B> @@ -37,7 +47,13 @@ int </B><I>type</I><B>);</B> <P><B>int pthread_mutexattr_getkind_np(const pthread_mutexattr_t *</B><I>attr</I><B>, int *</B><I>type</I><B>);</B> </P> -<H2><A HREF="#toc2" NAME="sect2">Description</A></H2> +<P><B>int pthread_mutexattr_setrobust(pthread_mutexattr_t *</B><I>attr</I><B>, +int</B><SPAN STYLE="font-weight: normal"> </SPAN><I><SPAN STYLE="font-weight: normal">robust</SPAN></I><B>);</B> +</P> +<P><B>int pthread_mutexattr_getrobust(pthread_mutexattr_t *</B><I>attr</I><B>, +int</B><SPAN STYLE="font-weight: normal"> </SPAN><B>*</B><I><SPAN STYLE="font-weight: normal">robust</SPAN></I><B>);</B> +</P> +<H2 CLASS="western"><A HREF="#toc2" NAME="sect2">Description</A></H2> <P>Mutex attributes can be specified at mutex creation time, by passing a mutex attribute object as second argument to <A HREF="pthread_mutex_init.html"><B>pthread_mutex_init</B>(3)</A> . @@ -50,12 +66,27 @@ attributes. </P> <P><B>pthread_mutexattr_destroy</B> destroys a mutex attribute object, which must not be reused until it is reinitialized.</P> +<P><B>pthread_mutexattr_settype</B> sets the mutex type attribute in +<I>attr</I> to the value specified by <I>type</I>. +</P> +<P><B>pthread_mutexattr_gettype</B> retrieves the current value of +the mutex kind attribute in <I>attr</I> and stores it in the location +pointed to by <I>type</I>. +</P> +<P><B>Pthreads-w32</B> also recognises the following equivalent +functions that are used in Linux:</P> +<P><B>pthread_mutexattr_setkind_np</B> is an alias for +<B>pthread_mutexattr_settype</B>. +</P> +<P STYLE="font-weight: normal"><B>pthread_mutexattr_getkind_np</B> is +an alias for <B>pthread_mutexattr_gettype</B>. +</P> <P>The following mutex types are supported:</P> -<P STYLE="margin-left: 2cm"><B>PTHREAD_MUTEX_NORMAL</B> - for +<P STYLE="margin-left: 0.79in"><B>PTHREAD_MUTEX_NORMAL</B> - for ‘‘fast’’ mutexes.</P> -<P STYLE="margin-left: 2cm"><B>PTHREAD_MUTEX_RECURSIVE</B> - for +<P STYLE="margin-left: 0.79in"><B>PTHREAD_MUTEX_RECURSIVE</B> - for ‘‘recursive’’ mutexes.</P> -<P STYLE="margin-left: 2cm"><B>PTHREAD_MUTEX_ERRORCHECK</B> - for +<P STYLE="margin-left: 0.79in"><B>PTHREAD_MUTEX_ERRORCHECK</B> - for ‘‘error checking’’ mutexes.</P> <P>The mutex type determines what happens if a thread attempts to lock a mutex it already owns with <A HREF="pthread_mutex_lock.html"><B>pthread_mutex_lock</B>(3)</A> @@ -75,83 +106,102 @@ state. <P>The default mutex type is <B>PTHREAD_MUTEX_NORMAL</B></P> <P><B>Pthreads-w32</B> also recognises the following equivalent types that are used by Linux:</P> -<P STYLE="margin-left: 2cm; font-weight: medium"><B>PTHREAD_MUTEX_FAST_NP</B> +<P STYLE="margin-left: 0.79in; font-weight: normal"><B>PTHREAD_MUTEX_FAST_NP</B> – equivalent to <B>PTHREAD_MUTEX_NORMAL</B></P> -<P STYLE="margin-left: 2cm"><B>PTHREAD_MUTEX_RECURSIVE_NP</B></P> -<P STYLE="margin-left: 2cm"><B>PTHREAD_MUTEX_ERRORCHECK_NP</B></P> -<P><B>pthread_mutexattr_settype</B> sets the mutex type attribute in -<I>attr</I> to the value specified by <I>type</I>. -</P> -<P><B>pthread_mutexattr_gettype</B> retrieves the current value of -the mutex kind attribute in <I>attr</I> and stores it in the location -pointed to by <I>type</I>. -</P> -<P><B>Pthreads-w32</B> also recognises the following equivalent -functions that are used in Linux:</P> -<P><B>pthread_mutexattr_setkind_np</B> is an alias for -<B>pthread_mutexattr_settype</B>. -</P> -<P STYLE="font-weight: medium"><B>pthread_mutexattr_getkind_np</B> is -an alias for <B>pthread_mutexattr_gettype</B>. -</P> -<H2><A HREF="#toc3" NAME="sect3">Return Value</A></H2> -<P><B>pthread_mutexattr_init</B>, <B>pthread_mutexattr_destroy</B> -and <B>pthread_mutexattr_gettype</B> always return 0. -</P> -<P><B>pthread_mutexattr_settype</B> returns 0 on success and a -non-zero error code on error. -</P> -<H2><A HREF="#toc4" NAME="sect4">Errors</A></H2> -<P>On error, <B>pthread_mutexattr_settype</B> returns the following -error code: -</P> +<P STYLE="margin-left: 0.79in"><B>PTHREAD_MUTEX_RECURSIVE_NP</B></P> +<P STYLE="margin-left: 0.79in"><B>PTHREAD_MUTEX_ERRORCHECK_NP</B></P> +<P><B>pthread_mutexattr_setrobust</B><SPAN STYLE="font-weight: normal"> +sets the robustness attribute to the value given by </SPAN><I><SPAN STYLE="font-weight: normal">robust</SPAN></I><SPAN STYLE="font-weight: normal">.</SPAN></P> +<P><B>pthread_mutexattr_getrobust</B><SPAN STYLE="font-weight: normal"> +returns the current robustness value to the location given by +*</SPAN><I><SPAN STYLE="font-weight: normal">robust</SPAN></I><SPAN STYLE="font-weight: normal">.</SPAN></P> +<P><SPAN STYLE="font-weight: normal">The possible values for </SPAN><I><SPAN STYLE="font-weight: normal">robust</SPAN></I><SPAN STYLE="font-weight: normal"> +are:</SPAN></P> +<P STYLE="margin-left: 0.79in"><B>PTHREAD_MUTEX_STALLED</B><SPAN STYLE="font-weight: normal"> +- 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.</SPAN></P> +<P STYLE="margin-left: 0.79in"><B>PTHREAD_MUTEX_ROBUST</B><SPAN STYLE="font-weight: normal"> +- 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.</SPAN></P> +<H2 CLASS="western"><A HREF="#toc3" NAME="sect3">Return Value</A></H2> +<P><SPAN STYLE="font-weight: normal">On success all functions return +0, otherwise they return an error code as follows:</SPAN></P> +<P><B>pthread_mutexattr_init</B></P> +<P STYLE="margin-left: 0.79in"><B>ENOMEM</B><SPAN STYLE="font-weight: normal"> +- insufficient memory for </SPAN><I><SPAN STYLE="font-weight: normal">attr</SPAN></I><SPAN STYLE="font-weight: normal">.</SPAN></P> +<P><B>pthread_mutexattr_destroy</B></P> +<P STYLE="margin-left: 0.79in"><B>EINVAL</B><SPAN STYLE="font-weight: normal"> +- </SPAN><I><SPAN STYLE="font-weight: normal">attr</SPAN></I><SPAN STYLE="font-weight: normal"> +is invalid.</SPAN></P> +<P><B>pthread_mutexattr_gettype</B></P> +<P STYLE="margin-left: 0.79in"><B>EINVAL</B><SPAN STYLE="font-weight: normal"> +- </SPAN><I><SPAN STYLE="font-weight: normal">attr</SPAN></I><SPAN STYLE="font-weight: normal"> +is invalid.</SPAN></P> +<P><B>pthread_mutexattr_settype</B></P> <DL> - <DT><B>EINVAL</B> - </DT><DD STYLE="margin-bottom: 0.5cm"> - <I>type</I> is none of:<BR><B>PTHREAD_MUTEX_NORMAL</B>, - <B>PTHREAD_MUTEX_FAST_NP</B>,<BR><B>PTHREAD_MUTEX_RECURSIVE</B>, - <B>PTHREAD_MUTEX_RECURSIVE_NP,<BR>PTHREAD_MUTEX_ERRORCHECK</B>, - <B>PTHREAD_MUTEX_ERRORCHECK_NP</B> + <DL> + <DL> + <DT><B>EINVAL</B><SPAN STYLE="font-weight: normal"> - </SPAN><I><SPAN STYLE="font-weight: normal">attr</SPAN></I><SPAN STYLE="font-weight: normal"> + is invalid or </SPAN><I><SPAN STYLE="font-weight: normal">type</SPAN></I><SPAN STYLE="font-weight: normal"> + is none of:</SPAN></DT><DL> + <DL> + <DT> + <B>PTHREAD_MUTEX_NORMAL<BR>PTHREAD_MUTEX_FAST_NP<BR>PTHREAD_MUTEX_RECURSIVE<BR>PTHREAD_MUTEX_RECURSIVE_NP<BR>PTHREAD_MUTEX_ERRORCHECK<BR>PTHREAD_MUTEX_ERRORCHECK_NP</B></DT></DL> + </DL> + </DL> + </DL> + <DD STYLE="margin-left: 0in"> + <BR> </DD></DL> -<H2> -<A HREF="#toc5" NAME="sect5">Author</A></H2> +<P> +<B>pthread_mutexattr_getrobust</B></P> +<P STYLE="margin-left: 0.79in"><B>EINVAL</B><SPAN STYLE="font-weight: normal"> +– </SPAN><I><SPAN STYLE="font-weight: normal">attr</SPAN></I><SPAN STYLE="font-weight: normal"> +or </SPAN><I><SPAN STYLE="font-weight: normal">robust</SPAN></I><SPAN STYLE="font-weight: normal"> +is invalid.</SPAN></P> +<P><B>pthread_mutexattr_setrobust</B></P> +<P STYLE="margin-left: 0.79in"><B>EINVAL</B><SPAN STYLE="font-weight: normal"> +– </SPAN><I><SPAN STYLE="font-weight: normal">attr</SPAN></I><SPAN STYLE="font-weight: normal"> +or </SPAN><I><SPAN STYLE="font-weight: normal">robust</SPAN></I><SPAN STYLE="font-weight: normal"> +is invalid.</SPAN></P> +<H2 CLASS="western"><A HREF="#toc5" NAME="sect5">Author</A></H2> <P>Xavier Leroy <Xavier.Leroy@inria.fr> </P> <P>Modified by Ross Johnson for use with <A HREF="http://sources.redhat.com/pthreads-win32">Pthreads-w32</A>.</P> -<H2><A HREF="#toc6" NAME="sect6">See Also</A></H2> +<H2 CLASS="western"><A HREF="#toc6" NAME="sect6">See Also</A></H2> <P><A HREF="pthread_mutex_init.html"><B>pthread_mutex_init</B>(3)</A> , <A HREF="pthread_mutex_lock.html"><B>pthread_mutex_lock</B>(3)</A> , <A HREF="pthread_mutex_unlock.html"><B>pthread_mutex_unlock</B>(3)</A> . </P> -<H2><A HREF="#toc7" NAME="sect7"><U><FONT COLOR="#000080">Notes</FONT></U></A></H2> +<H2 CLASS="western"><A HREF="#toc7" NAME="sect7"><FONT COLOR="#000080"><U>Notes</U></FONT></A></H2> <P>For speed, <B>Pthreads-w32</B> never checks the thread ownership -of mutexes of type <B>PTHREAD_MUTEX_NORMAL</B> (or +of non-robust mutexes of type <B>PTHREAD_MUTEX_NORMAL</B> (or <B>PTHREAD_MUTEX_FAST_NP</B>) when performing operations on the mutex. It is therefore possible for one thread to lock such a mutex and another to unlock it.</P> -<P><SPAN STYLE="font-weight: medium">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.</SPAN></P> +<P STYLE="font-weight: normal">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.</P> <HR> <P><A NAME="toc"></A><B>Table of Contents</B></P> <UL> - <LI><P STYLE="margin-bottom: 0cm"><A HREF="#sect0" NAME="toc0">Name</A> + <LI><P STYLE="margin-bottom: 0in"><A HREF="#sect0" NAME="toc0">Name</A> </P> - <LI><P STYLE="margin-bottom: 0cm"><A HREF="#sect1" NAME="toc1">Synopsis</A> + <LI><P STYLE="margin-bottom: 0in"><A HREF="#sect1" NAME="toc1">Synopsis</A> </P> - <LI><P STYLE="margin-bottom: 0cm"><A HREF="#sect2" NAME="toc2">Description</A> + <LI><P STYLE="margin-bottom: 0in"><A HREF="#sect2" NAME="toc2">Description</A> </P> - <LI><P STYLE="margin-bottom: 0cm"><A HREF="#sect3" NAME="toc3">Return + <LI><P STYLE="margin-bottom: 0in"><A HREF="#sect3" NAME="toc3">Return Value</A> </P> - <LI><P STYLE="margin-bottom: 0cm"><A HREF="#sect4" NAME="toc4">Errors</A> - </P> - <LI><P STYLE="margin-bottom: 0cm"><A HREF="#sect5" NAME="toc5">Author</A> + <LI><P STYLE="margin-bottom: 0in"><A HREF="#sect5" NAME="toc5">Author</A> </P> - <LI><P STYLE="margin-bottom: 0cm"><A HREF="#sect6" NAME="toc6">See + <LI><P STYLE="margin-bottom: 0in"><A HREF="#sect6" NAME="toc6">See Also</A></P> <LI><P><A HREF="#sect7" NAME="toc7">Notes</A></P> </UL> </BODY> -</HTML> +</HTML>
\ No newline at end of file @@ -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" @@ -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 <sched.h> /* @@ -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 @@ -636,6 +644,12 @@ enum { PTHREAD_PROCESS_SHARED = 1, /* + * pthread_mutexattr_{get,set}robust + */ + PTHREAD_MUTEX_STALLED = 0, /* Default */ + PTHREAD_MUTEX_ROBUST = 1, + +/* * pthread_barrier_wait */ PTHREAD_BARRIER_SERIAL_THREAD = -1 @@ -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 <process.h> */ +#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 <ross.johnson at homemail.com.au> + + * 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 <ross.johnson at homemail.com.au> + + * sequence1.c: New test for new pthread_getsequence_np(). + +2011-03-24 Ross Johnson <ross.johnson at homemail.com.au> + + * 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 <ross.johnson at homemail.com.au> * 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 <sys/timeb.h> -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 <sys/timeb.h> -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 <sys/timeb.h> -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. */ |