diff options
| -rw-r--r-- | ANNOUNCE | 43 | ||||
| -rw-r--r-- | ChangeLog | 21 | ||||
| -rw-r--r-- | README.NONPORTABLE | 31 | ||||
| -rw-r--r-- | global.c | 6 | ||||
| -rw-r--r-- | implement.h | 34 | ||||
| -rw-r--r-- | mutex.c | 399 | ||||
| -rw-r--r-- | nonportable.c | 56 | ||||
| -rw-r--r-- | pthread.def | 3 | ||||
| -rw-r--r-- | pthread.h | 18 | 
9 files changed, 252 insertions, 359 deletions
@@ -55,24 +55,47 @@ New:          be different to some other implementations, eg
          Solaris.
 -        PTHREAD_MUTEX_NORMAL will simulate thread deadlock
 +        PTHREAD_MUTEX_NORMAL will cause thread deadlock
          if the owner of a mutex tries to relock it without
 -        first unlocking it, however the lock will be released
 -        if the owner thread is async-canceled.
 +        first unlocking it. It has slightly less overhead.
 --       Pthreads-win32 mutexes are now always based on
 -        Win32 critical sections. We no longer use Win32
 -        mutexes when TryEnterCriticalSection isn't
 -        supported.
 +        The behaviour of PTHREAD_MUTEX_DEFAULT can be
 +        remapped to any other type through the new
 +        non-portable function
 +
 +          pthread_mutex_setdefaulttype_np()
 +
 +        (see README.NONPORTABLE)
 +
 +        Remapping only effects newly initialised mutexes.
 +        So if you want behaviour more like Solaris
 +        POSIX mutexes, which are non-recursive by default,
 +        you can call this at the start of your application:
 +
 +        int previousType;
 +        pthread_mutex_setdefaulttype_np(PTHREAD_MUTEX_ERRORCHECK,
 +                                        &previousType);
 +
 +-       Pthreads-win32 mutexes are now based on Win32
 +        critical sections for all Windows versions. We no longer
 +        depend on TryEnterCriticalSection.
          - Thomas Pfaff <tpfaff@gmx.net>
 +        This may change again before the next snapshot
 +        to rely solely on Win32's Interlocked* routines.
 +
  Bugs fixed:
 +-       Pthread_mutex_trylock() now properly returns EBUSY
 +        even when the current thread owns the mutex.
 +        Consequently, pthread_mutex_destroy() will no longer
 +        destroy a locked mutex (it will return EBUSY).
 +        - Thomas Pfaff <tpfaff@gmx.net>
 +
  -       The condition variable and read-write lock functions
 -        have been improved. For details re the [fixed] problems
 -        in the CV implementation see the file README.CV
 +        have been improved. For discussion re the [fixed]
 +        problems in the CV implementation see the file README.CV
          - Alexander Terekhov <TEREKHOV@de.ibm.com>
 -
  Known bugs in this snapshot
  ---------------------------
 @@ -1,3 +1,24 @@ +2001-02-09  Ross Johnson  <rpj@setup1.ise.canberra.edu.au>
 +
 +	* nonportable.c (pthread_mutex_setdefaulttype_np): New
 +	function for changing the default mutex type.
 +
 +	* mutex.c (ptw32_InitializeCriticalSection): Removed.
 +	(ptw32_InitializeCriticalSection): Removed.
 +	(ptw32_InitializeCriticalSection): Removed.
 +	(ptw32_InitializeCriticalSection): Removed.
 +	(ptw32_InitializeCriticalSection): Removed.
 +	(pthread_mutex_init): Apply Thomas Pfaff's original
 +	patches but altered slightly to avoid using
 +	critical sections and retain/adapt for different
 +	mutex types (see log entry for 2001-01-10).
 +	(pthread_mutex_destroy): Likewise.
 +	(pthread_mutex_lock): Likewise.
 +	(pthread_mutex_unlock): Likewise.
 +	(pthread_mutex_trylock): Likewise.
 +
 +	* Tagged repository 'exp-2001-02-09-passed'.
 +	
  2001-02-09  Ross Johnson  <rpj@special.ise.canberra.edu.au>
  	* sched.c (pthread_setconcurrency): Moved to misc.c.
 diff --git a/README.NONPORTABLE b/README.NONPORTABLE index 7dfba7f..8319853 100644 --- a/README.NONPORTABLE +++ b/README.NONPORTABLE @@ -40,6 +40,37 @@ pthread_delay_np (const struct timespec *interval);          0          Successful completion.           [EINVAL]   The value specified by interval is invalid.  +int +pthread_mutex_setdefaulttype_np (int newtype, int * oldtype); + +        The routine sets the default type to be given to all +        POSIX mutexes initialised after the function +        is called. Any of the following type values +        can be made the default type: + +          PTHREAD_MUTEX_NORMAL +          PTHREAD_MUTEX_ERRORCHECK +          PTHREAD_MUTEX_RECURSIVE +          PTHREAD_MUTEX_DEFAULT + +        Any mutex initialised with type PTHREAD_MUTEX_DEFAULT +        will be set to the mapped type instead. Previously +        initialised mutexes are not changed. + +        When set to PTHREAD_MUTEX_DEFAULT (the initial +        value), mutexes will behave as for the +        PTHREAD_MUTEX_RECURSIVE type. + +        If 'oldtype' is a non-NULL pointer, the previous type is +        returned through it. +        To get the previous type without setting a new type, +        use -1 as the 'newtype' value. + +        Return Values + +        0          Successfully changed to new type. +        [EINVAL]   New type isn't valid. +  BOOL  pthread_win32_process_attach_np (void); @@ -54,3 +54,9 @@ CRITICAL_SECTION ptw32_cond_test_init_lock;   * created read/write locks.   */  CRITICAL_SECTION ptw32_rwlock_test_init_lock; + +/* + * The default mutex type can be remapped by teh application + * via the pthread_mutex_setdefaulttype_np() function. + */ +int ptw32_mutex_mapped_default = PTHREAD_MUTEX_DEFAULT; diff --git a/implement.h b/implement.h index 165708a..a1a52f8 100644 --- a/implement.h +++ b/implement.h @@ -121,33 +121,17 @@ struct pthread_attr_t_ {  #define PTW32_OBJECT_AUTO_INIT ((void *) -1)  #define PTW32_OBJECT_INVALID   NULL -/* - * Our own critical section type, used - * when the system doesn't support TryEnterCriticalSection() - */ -typedef struct ptw32_cs_t_ { -  int valid; -  pthread_t owner; -  long lock_idx; -  long entered_count; -} ptw32_cs_t; - -typedef union ptw32_cs_u_t_ { -  CRITICAL_SECTION cs; -  ptw32_cs_t csFake; -} ptw32_cs_u_t; -  struct pthread_mutexattr_t_ {    int pshared;    int type;  };  struct pthread_mutex_t_ { -  ptw32_cs_u_t cs; -  int lockCount; +  int lock_idx; +  int try_lock;    int pshared;    int type; -  pthread_t ownerThread; +  pthread_t owner;  };  struct pthread_key_t_ { @@ -324,7 +308,7 @@ extern CRITICAL_SECTION ptw32_mutex_test_init_lock;  extern CRITICAL_SECTION ptw32_cond_test_init_lock;  extern CRITICAL_SECTION ptw32_rwlock_test_init_lock;  extern BOOL (WINAPI *ptw32_try_enter_critical_section)(LPCRITICAL_SECTION); - +extern int ptw32_mutex_mapped_default;  /* Declared in misc.c */  #ifdef NEED_CALLOC @@ -380,16 +364,6 @@ BOOL ptw32_increase_semaphore(sem_t * sem,                                   unsigned int n);  #endif /* NEED_SEM */ -int ptw32_InitializeCriticalSection (ptw32_cs_u_t *); - -void ptw32_DeleteCriticalSection (ptw32_cs_u_t *); - -void ptw32_EnterCriticalSection (ptw32_cs_u_t *); - -void ptw32_LeaveCriticalSection (ptw32_cs_u_t *); - -BOOL ptw32_TryEnterCriticalSection (ptw32_cs_u_t *); -  #ifdef __cplusplus  }  #endif /* __cplusplus */ @@ -85,252 +85,6 @@ ptw32_mutex_check_need_init(pthread_mutex_t *mutex)  } -/* - * The following internal versions of *CriticalSection() - * include an implementation of TryEnterCriticalSection - * for platforms on which that function has not been - * provided by Microsoft (eg. W95/98). This allows us - * to avoid using Win32 mutexes as the basis - * of our implementation of POSIX mutex locks. - * - * Where TryEnterCriticalSection() is provided by the - * platform, these routines act as wrappers with - * minimal additional overhead. Otherwise, these - * routines manage additional state in order to - * properly emulate TryEnterCriticalSection(). - */ - -int -ptw32_InitializeCriticalSection (ptw32_cs_u_t * csect) -     /* -      * ------------------------------------------------------ -      * -      * PARAMETERS -      *      csect -      *              pointer to an instance of ptw32_cs_u_t -      *              csect->csFake must be NULL on entry. -      * -      * DESCRIPTION -      *      Internal implementation of InitializeCriticalSection. -      * -      * RETURN -      *      0       Initialisation successful -      *      EINVAL  csFake already initialised -      *  -      * ------------------------------------------------------ -      */ -{ -  int result = 0; - -  if (NULL != ptw32_try_enter_critical_section) -    { -      InitializeCriticalSection(&csect->cs); -    } -  else -    { -      while (InterlockedIncrement(&csect->csFake.lock_idx) > 0) -        { -          InterlockedDecrement(&csect->csFake.lock_idx); -          Sleep(0); -        } - -	if (csect->csFake.valid) -        { -          result = EINVAL; -        } -      else -        { -           csect->csFake.owner = NULL; -           csect->csFake.entered_count = 0; -           csect->csFake.valid = 1; -        } - -      InterlockedDecrement(&csect->csFake.lock_idx); -    } - -  return result; -} - -void -ptw32_DeleteCriticalSection (ptw32_cs_u_t * csect) -     /* -      * ------------------------------------------------------ -      * -      * PARAMETERS -      *      csect -      *              pointer to an instance of ptw32_cs_u_t -      * -      * DESCRIPTION -      *      Internal implementation of DeleteCriticalSection. -      *  -      * ------------------------------------------------------ -      */ -{ -  if (NULL != ptw32_try_enter_critical_section) -    { -      DeleteCriticalSection(&csect->cs); -    } -  else -    { -      while (InterlockedIncrement(&csect->csFake.lock_idx) > 0) -        { -          InterlockedDecrement(&csect->csFake.lock_idx); -          Sleep(0); -        } - -      if (csect->csFake.valid -          && csect->csFake.entered_count == 0) -        { -          csect->csFake.valid = 0; -        } - -      InterlockedDecrement(&csect->csFake.lock_idx); -    } -} - -void -ptw32_EnterCriticalSection(ptw32_cs_u_t * csect) -     /* -      * ------------------------------------------------------ -      * -      * PARAMETERS -      *      csect -      *              pointer to an instance of ptw32_cs_u_t -      * -      * DESCRIPTION -      *      Internal implementation of EnterCriticalSection. -      *  -      * ------------------------------------------------------ -      */ -{ -  if (NULL != ptw32_try_enter_critical_section) -    { -      EnterCriticalSection(&csect->cs); -    } -  else -    { -      pthread_t self = pthread_self(); - -      while (InterlockedIncrement(&csect->csFake.lock_idx) >= 0 -             && csect->csFake.valid -             && csect->csFake.owner != NULL -             && csect->csFake.owner != self) -        { -          InterlockedDecrement(&csect->csFake.lock_idx); -          Sleep(0); -        } - -      if (csect->csFake.valid) -        { -          csect->csFake.entered_count++; -          csect->csFake.owner = self; -        } - -      InterlockedDecrement(&csect->csFake.lock_idx); -    } -} - -void -ptw32_LeaveCriticalSection (ptw32_cs_u_t * csect) -     /* -      * ------------------------------------------------------ -      * -      * PARAMETERS -      *      csect -      *              pointer to an instance of ptw32_cs_u_t -      * -      * DESCRIPTION -      *      Internal implementation of LeaveCriticalSection. -      *  -      * ------------------------------------------------------ -      */ -{ -  if (NULL != ptw32_try_enter_critical_section) -    { -      LeaveCriticalSection(&csect->cs); -    } -  else -    { -      while (InterlockedIncrement(&csect->csFake.lock_idx) > 0) -        { -          InterlockedDecrement(&csect->csFake.lock_idx); -          Sleep(0); -        } - -      if (csect->csFake.valid) -        { -          csect->csFake.entered_count--; -          if (csect->csFake.entered_count == 0) -            { -              csect->csFake.owner = NULL; -            } -        } - -      InterlockedDecrement(&csect->csFake.lock_idx); -    } -} - -BOOL -ptw32_TryEnterCriticalSection (ptw32_cs_u_t * csect) -     /* -      * ------------------------------------------------------ -      * -      * PARAMETERS -      *      csect -      *              pointer to an instance of ptw32_cs_u_t -      * -      * DESCRIPTION -      *      Internal implementation of TryEnterCriticalSection. -      *  -      * RETURNS -      *      FALSE              Current thread doesn't own the -      *                         lock, -      *      TRUE               Current thread owns the lock -      *                         (if the current thread already -      *                          held the lock then we recursively -      *                          enter). -      * ------------------------------------------------------ -      */ -{ -  BOOL result = FALSE; - -  if (NULL != ptw32_try_enter_critical_section) -    { -      result = (*ptw32_try_enter_critical_section)(&csect->cs); -    } -  else -    { -      pthread_t self; - -      while (InterlockedIncrement(&csect->csFake.lock_idx) > 0) -        { -          InterlockedDecrement(&csect->csFake.lock_idx); -          Sleep(0); -        } - -      self = pthread_self(); - -      if (csect->csFake.valid -          && (csect->csFake.owner == NULL || csect->csFake.owner == self)) -        { -          /*  -           * The semantics of TryEnterCriticalSection -           * (according to the documentation at MS) -           * are that the CS is entered recursively -           * if the thread is the current owner. -           */ -          csect->csFake.entered_count++; -          csect->csFake.owner = self; -          result = TRUE; -        } - -      InterlockedDecrement(&csect->csFake.lock_idx); -    } - -  return result; -} - -  int  pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)  { @@ -349,16 +103,9 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)        goto FAIL0;      } -  mx->cs.csFake.lock_idx = -1; - -  result = ptw32_InitializeCriticalSection(&mx->cs); -  if (result != 0) -    { -      goto FAIL1; -    } - -  mx->lockCount = 0; -  mx->ownerThread = NULL; +  mx->lock_idx = -1; +  mx->owner = NULL; +  mx->try_lock = 0;    if (attr != NULL && *attr != NULL)      { @@ -393,7 +140,11 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)        mx->pshared = PTHREAD_PROCESS_PRIVATE;      } -FAIL1: +  if (mx->type == PTHREAD_MUTEX_DEFAULT) +    { +      mx->type = ptw32_mutex_mapped_default; +    } +    if (result != 0 && mx != NULL)      {        free(mx); @@ -428,7 +179,7 @@ pthread_mutex_destroy(pthread_mutex_t *mutex)         * Check to see if the mutex is held by any thread. We         * can't destroy it if it is. Pthread_mutex_trylock is         * not recursive and will return EBUSY even if the current -       * thread (us) holds the lock. +       * thread holds the lock.         */        result = pthread_mutex_trylock(&mx); @@ -447,7 +198,6 @@ pthread_mutex_destroy(pthread_mutex_t *mutex)            if (result == 0)              { -              ptw32_DeleteCriticalSection(&mx->cs);                free(mx);              }            else @@ -892,53 +642,66 @@ pthread_mutex_lock(pthread_mutex_t *mutex)        switch (mx->type)          { -        case PTHREAD_MUTEX_NORMAL: -          if (pthread_equal(mx->ownerThread, self)) +        case PTHREAD_MUTEX_DEFAULT: +        case PTHREAD_MUTEX_RECURSIVE: +          if (InterlockedIncrement(&mx->lock_idx) > 0)              { -              /* -               * Pretend to be deadlocked but release the -               * mutex if we are [asynchronously] canceled. -               */ -              pthread_cleanup_push(pthread_mutex_unlock, (void *) mutex); -              while (TRUE) +              while (mx->try_lock)                  {                    Sleep(0);                  } -              pthread_cleanup_pop(1); -              /* -               * Never gets beyond here. -               */ +              while (mx->lock_idx > 0 && mx->owner != self) +                { +                  Sleep(0); +                }              } -          else +          mx->owner = self; +          break; +        case PTHREAD_MUTEX_NORMAL: +          /* +           * If the thread already owns the mutex +           * then the thread will become deadlocked. +           */ +          while (InterlockedIncrement(&mx->lock_idx) > 0)              { -              ptw32_EnterCriticalSection(&mx->cs); +              InterlockedDecrement(&mx->lock_idx); +              Sleep(0);              } +          mx->owner = self;            break;          case PTHREAD_MUTEX_ERRORCHECK: -          if (pthread_equal(mx->ownerThread, self)) +          if (0 == InterlockedIncrement(&mx->lock_idx))              { -              result = EDEADLK; +              mx-owner = self;              }            else              { -              ptw32_EnterCriticalSection(&mx->cs); +              while (mx->try_lock) +                { +                  Sleep(0); +                } + +              while (mx->lock_idx > 0 && mx->owner != self) +                { +                  Sleep(0); +                } + +              if (mx->owner == self) +                { +                  InterlockedDecrement(&mx->lock_idx); +                  result = EDEADLK; +                } +              else +                { +                  mx->owner = self; +                }              }            break; -        case PTHREAD_MUTEX_DEFAULT: -        case PTHREAD_MUTEX_RECURSIVE: -          ptw32_EnterCriticalSection(&mx->cs); -          break;          default:            result = EINVAL;            break;          } - -      if (result == 0) -        { -          mx->ownerThread = self; -          mx->lockCount++; -        }      }    return result; @@ -964,17 +727,25 @@ pthread_mutex_unlock(pthread_mutex_t *mutex)     */    if (mx != (pthread_mutex_t) PTW32_OBJECT_AUTO_INIT)      { -      if (pthread_equal(mx->ownerThread, pthread_self())) +      if (mx->owner == pthread_self())  	{ -        mx->lockCount--; - -	  if (mx->lockCount == 0) -	    { -	      mx->ownerThread = NULL; -	    } +          switch (mx->type) +            { +            case PTHREAD_MUTEX_NORMAL: +            case PTHREAD_MUTEX_ERRORCHECK: +              mx->owner = NULL; +              break; +            case PTHREAD_MUTEX_RECURSIVE: +            default: +              if (mx->lock_idx == 0) +                { +                  mx->owner = NULL; +                } +              break; +            } -        ptw32_LeaveCriticalSection(&mx->cs); -	} +          InterlockedDecrement(&mx->lock_idx); +        }        else  	{  	  result = EPERM; @@ -1012,28 +783,34 @@ pthread_mutex_trylock(pthread_mutex_t *mutex)      }    mx = *mutex; -  self = pthread_self();    if (result == 0)      { +      self = pthread_self();        /* -       * TryEnterCriticalSection is a little different to -       * the POSIX trylock semantics. Trylock returns -       * EBUSY even if the calling thread already owns -       * the mutex - it doesn't lock it recursively, even +       * Trylock returns EBUSY if the mutex is held already, +       * even if the current thread owns the mutex - ie. it +       * doesn't lock it recursively, even         * if the mutex type is PTHREAD_MUTEX_RECURSIVE.         */ -      if (ptw32_TryEnterCriticalSection(&mx->cs)) +      if (0 == (mx->lock_idx + 1))          { -          /* -           * We now own the lock, but check that we don't -           * already own the mutex. -           */ -          if (pthread_equal(mx->ownerThread, self)) +          mx->try_lock++; + +          if (0 == InterlockedIncrement(&mx->lock_idx))              { -              ptw32_LeaveCriticalSection(&mx->cs); -              result = EBUSY; +              mx->owner = self; +            } +          else +            { +              InterlockedDecrement(&mx->lock_idx); +              if (mx->owner == self) +                { +                  result = EBUSY; +                }              } + +          mx->try_lock--;          }        else          { @@ -1041,12 +818,6 @@ pthread_mutex_trylock(pthread_mutex_t *mutex)          }      } -  if (result == 0) -    { -      mx->ownerThread = self; -      mx->lockCount++; -    } -    return result;  } diff --git a/nonportable.c b/nonportable.c index 17cbc60..27b67df 100644 --- a/nonportable.c +++ b/nonportable.c @@ -248,3 +248,59 @@ pthread_win32_thread_detach_np ()    return TRUE;  } + + +/* + * pthread_mutex_setdefaulttype_np -- + * + * Sets the default type to be given to all + * POSIX mutexes initialised after the function + * is called. Any of the following type values + * can be made the default type: + * + *   PTHREAD_MUTEX_NORMAL + *   PTHREAD_MUTEX_ERRORCHECK + *   PTHREAD_MUTEX_RECURSIVE + *   PTHREAD_MUTEX_DEFAULT + * + * Any mutex initialised with type PTHREAD_MUTEX_DEFAULT + * will be set to the mapped type instead. Previously + * initialised mutexes are not changed. + * + * When set to PTHREAD_MUTEX_DEFAULT (the initial + * value), mutexes will behave as for the + * PTHREAD_MUTEX_RECURSIVE type. + * + * If 'oldtype' is a non-NULL pointer, the previous type is + * returned through it. + * To get the previous type without setting a new type, + * use -1 as the 'newtype' value. Of course, the following: + * + *   pthread_mutex_setdefaulttype_np(-1, NULL); + * + * is then an extravagant equivalent to the value 0 (zero). + */ +int +pthread_mutex_setdefaulttype_np (int newtype, int * oldtype) +{ +  int result = 0; + +  if (oldtype != NULL) +    { +      *oldType = ptw32_mutex_mapped_default; +    } + +  switch (newtype) +    { +    case PTHREAD_MUTEX_DEFAULT: +    case PTHREAD_MUTEX_NORMAL: +    case PTHREAD_MUTEX_ERRORCHECK: +    case PTHREAD_MUTEX_RECURSIVE: +      ptw32_mutex_mapped_default = newtype; +      break; +    default: +      result = EINVAL; +    } + +  return result; +} diff --git a/pthread.def b/pthread.def index 580caf5..b16aba7 100644 --- a/pthread.def +++ b/pthread.def @@ -1,5 +1,5 @@  ; pthread.def
 -; Last updated: $Date: 2001/02/06 05:44:38 $
 +; Last updated: $Date: 2001/02/09 06:51:30 $
  ; Currently unimplemented functions are commented out.
 @@ -107,6 +107,7 @@ pthread_rwlock_unlock  ;
  pthread_getw32threadhandle_np
  pthread_delay_np
 +pthread_mutex_setdefaulttype_np
  pthreadCancelableWait
  pthreadCancelableTimedWait
  ; For use when linking statically
 @@ -631,10 +631,10 @@ int pthread_attr_setschedparam (pthread_attr_t *attr,  				const struct sched_param *param);  int pthread_attr_setscope (pthread_attr_t *, -                       int); +                           int);  int pthread_attr_getscope (const pthread_attr_t *, -                       int *); +                           int *);  /*   * PThread Functions @@ -793,10 +793,19 @@ int pthread_rwlock_unlock(pthread_rwlock_t *lock);   * Non-portable functions   */ -/* Possibly supported by other POSIX threads implimentations */ +/* + * Possibly supported by other POSIX threads implimentations + */  int pthread_delay_np (struct timespec * interval);  /* + * Remaps the default mutex type to any of the + * other possible types. Returns the previous type. + */ +int pthread_mutex_setdefaulttype_np (int newtype, +                                     int * oldtype); + +/*   * Returns the Win32 thread HANDLE associated   * with the given POSIX thread.   */ @@ -828,7 +837,8 @@ int pthread_win32_thread_detach_np(void);   * WaitForMultipleObjects.   */  int pthreadCancelableWait (HANDLE waitHandle); -int pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout); +int pthreadCancelableTimedWait (HANDLE waitHandle, +                                DWORD timeout);  /*   * Thread-Safe C Runtime Library Mappings.  | 
