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