diff options
| author | rpj <rpj> | 1998-12-22 15:59:24 +0000 | 
|---|---|---|
| committer | rpj <rpj> | 1998-12-22 15:59:24 +0000 | 
| commit | 95aa0a376d93ee021a6c085c71418e9f16513e0a (patch) | |
| tree | f05f436e30d759df3af5cfe9e2cde62e3efa6f1b | |
| parent | 4650bcf1f1efd88a0c8f502c28945bfabd7ef6db (diff) | |
Sun Dec 20 14:51:58 1998  Ross Johnson  <rpj@ixobrychus.canberra.edu.au>
        * misc.c (pthreadCancelableWait): New function by John Bossom. Non-stand
ard
        but provides a hook that can be used to implement cancellation points in
        applications that use this library.
        * pthread.h (pthread_cleanup_pop): C++ (non-WIN32) version uses
        try/catch to emulate John Bossom's WIN32 __try/__finally behaviour.
        In the WIN32 version __finally block, add a test for AbnormalTermination
 otherwise
        cleanup is only run if the cleanup_pop execute arg is non-zero. Cancella
tion
        should cause the cleanup to run irrespective of the execute arg.
        * condvar.c (pthread_condattr_init): Replaced by John Bossom's version.
        (pthread_condattr_destroy): Replaced by John Bossom's version.
        (pthread_condattr_getpshared): Replaced by John Bossom's version.
        (pthread_condattr_setpshared): Replaced by John Bossom's version.
        (pthread_cond_init): Replaced by John Bossom's version.
        Fix comment (refered to mutex rather than condition variable).
        (pthread_cond_destroy): Replaced by John Bossom's version.
        (pthread_cond_wait): Replaced by John Bossom's version.
        (pthread_cond_timedwait): Replaced by John Bossom's version.
        (pthread_cond_signal): Replaced by John Bossom's version.
        (pthread_cond_broadcast): Replaced by John Bossom's version.
Thu Dec 17 19:10:46 1998  Ross Johnson  <rpj@ixobrychus.canberra.edu.au>
        * tsd.c (pthread_key_create): Replaced by John Bossom's version.
        (pthread_key_delete): Replaced by John Bossom's version.
        (pthread_setspecific): Replaced by John Bossom's version.
        (pthread_getspecific): Replaced by John Bossom's version.
Mon Dec  7 09:44:40 1998  Ross Johnson  <rpj@ixobrychus.canberra.edu.au>
        * cancel.c (pthread_setcancelstate): Replaced by John Bossom's version.
        (pthread_setcanceltype): Replaced by John Bossom's version.
        (pthread_testcancel): Replaced by John Bossom's version.
        (pthread_cancel): Replaced by John Bossom's version.
        * exit.c (pthread_exit): Replaced by John Bossom's version.
        * misc.c (pthread_self): Replaced by John Bossom's version.
        (pthread_equal): Replaced by John Bossom's version.
        * sync.c (pthread_detach): Replaced by John Bossom's version.
        (pthread_join): Replaced by John Bossom's version.
        * create.c (pthread_create): Replaced by John Bossom's version.
        * private.c (_pthread_processInitialize): New by John Bossom.
        (_pthread_processTerminate): Non-public function by John Bossom.
        (_pthread_threadStart): Non-public function by John Bossom.
        (_pthread_threadDestroy): Non-public function by John Bossom.
        (_pthread_cleanupStack): Non-public function by John Bossom.
        (_pthread_tkAssocCreate): Non-public function by John Bossom.
        (_pthread_tkAssocDestroy): Non-public function by John Bossom.
        (_pthread_callUserDestroyRoutines): Non-public function by John Bossom.
        * implement.h: Added John Bossom's non-API structures and
        declarations.
        * dll.c (PthreadsEntryPoint): Cast return value of GetProcAddress
        to resolve compile warning from MSVC.
        * dll.c (DLLmain): Replaced by John Bossom's version.
        * dll.c (PthreadsEntryPoint):
        Re-applied Anders Norlander's patch:-
        Initialize _pthread_try_enter_critical_section at startup
        and release kernel32 handle when DLL is being unloaded.
| -rw-r--r-- | ChangeLog | 68 | ||||
| -rw-r--r-- | MAINTAINERS | 2 | ||||
| -rw-r--r-- | cancel.c | 241 | ||||
| -rw-r--r-- | condvar.c | 705 | ||||
| -rw-r--r-- | create.c | 146 | ||||
| -rw-r--r-- | dll.c | 113 | ||||
| -rw-r--r-- | exit.c | 43 | ||||
| -rw-r--r-- | global.c | 10 | ||||
| -rw-r--r-- | implement.h | 273 | ||||
| -rw-r--r-- | misc.c | 210 | ||||
| -rw-r--r-- | private.c | 411 | ||||
| -rw-r--r-- | pthread.h | 949 | ||||
| -rw-r--r-- | sync.c | 121 | ||||
| -rw-r--r-- | tsd.c | 307 | 
14 files changed, 3344 insertions, 255 deletions
| @@ -1,19 +1,79 @@ -1998-12-11  Ben Elliston  <bje@toilet.to.cygnus.com> - -	* README: Update info about subscribing to the mailing list. +Sun Dec 20 14:51:58 1998  Ross Johnson  <rpj@ixobrychus.canberra.edu.au> + +	* misc.c (pthreadCancelableWait): New function by John Bossom. Non-standard +	but provides a hook that can be used to implement cancellation points in +	applications that use this library. + +	* pthread.h (pthread_cleanup_pop): C++ (non-WIN32) version uses +	try/catch to emulate John Bossom's WIN32 __try/__finally behaviour. +	In the WIN32 version __finally block, add a test for AbnormalTermination otherwise +	cleanup is only run if the cleanup_pop execute arg is non-zero. Cancellation +	should cause the cleanup to run irrespective of the execute arg. + +	* condvar.c (pthread_condattr_init): Replaced by John Bossom's version. +	(pthread_condattr_destroy): Replaced by John Bossom's version. +	(pthread_condattr_getpshared): Replaced by John Bossom's version. +	(pthread_condattr_setpshared): Replaced by John Bossom's version. +	(pthread_cond_init): Replaced by John Bossom's version. +	Fix comment (refered to mutex rather than condition variable). +	(pthread_cond_destroy): Replaced by John Bossom's version. +	(pthread_cond_wait): Replaced by John Bossom's version. +	(pthread_cond_timedwait): Replaced by John Bossom's version. +	(pthread_cond_signal): Replaced by John Bossom's version. +	(pthread_cond_broadcast): Replaced by John Bossom's version. + +Thu Dec 17 19:10:46 1998  Ross Johnson  <rpj@ixobrychus.canberra.edu.au> + +	* tsd.c (pthread_key_create): Replaced by John Bossom's version. +	(pthread_key_delete): Replaced by John Bossom's version. +	(pthread_setspecific): Replaced by John Bossom's version. +	(pthread_getspecific): Replaced by John Bossom's version.  Mon Dec  7 09:44:40 1998  Ross Johnson  <rpj@ixobrychus.canberra.edu.au> +	* cancel.c (pthread_setcancelstate): Replaced by John Bossom's version. +	(pthread_setcanceltype): Replaced by John Bossom's version. +	(pthread_testcancel): Replaced by John Bossom's version. +	(pthread_cancel): Replaced by John Bossom's version. +	 +	* exit.c (pthread_exit): Replaced by John Bossom's version. + +	* misc.c (pthread_self): Replaced by John Bossom's version. +	(pthread_equal): Replaced by John Bossom's version. + +	* sync.c (pthread_detach): Replaced by John Bossom's version. +	(pthread_join): Replaced by John Bossom's version. + +	* create.c (pthread_create): Replaced by John Bossom's version. + +	* private.c (_pthread_processInitialize): New by John Bossom. +	(_pthread_processTerminate): Non-public function by John Bossom. +	(_pthread_threadStart): Non-public function by John Bossom. + 	(_pthread_threadDestroy): Non-public function by John Bossom. +	(_pthread_cleanupStack): Non-public function by John Bossom. +	(_pthread_tkAssocCreate): Non-public function by John Bossom. +	(_pthread_tkAssocDestroy): Non-public function by John Bossom. +	(_pthread_callUserDestroyRoutines): Non-public function by John Bossom. + +	* implement.h: Added John Bossom's non-API structures and +	declarations. +  	* dll.c (PthreadsEntryPoint): Cast return value of GetProcAddress  	to resolve compile warning from MSVC. +	* dll.c (DLLmain): Replaced by John Bossom's version. +	* dll.c (PthreadsEntryPoint): +	Re-applied Anders Norlander's patch:- +	Initialize _pthread_try_enter_critical_section at startup +	and release kernel32 handle when DLL is being unloaded. +  Sun Dec  6 21:54:35 1998  Ross Johnson  <rpj@ixobrychus.canberra.edu.au>  	* buildlib.bat: Fix args to CL when building the .DLL  	* cleanup.c (_pthread_destructor_run_all): Fix TSD key management.  	This is a tidy-up before TSD and Thread management is completely -	replaced by John Bossom's much more elegant code. +	replaced by John Bossom's code.  	* tsd.c (pthread_key_create): Fix TSD key management. diff --git a/MAINTAINERS b/MAINTAINERS index 3baf225..a09e2c5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8,3 +8,5 @@ Ross Johnson					rpj@ise.canberra.edu.au  Active contributors  Robert Colquhoun				rjc@trump.net.au +John E. Bossom					John.Bossom@cognos.com +Anders Norlander				anorland@hem2.passagen.se @@ -10,6 +10,245 @@  #include "pthread.h"  #include "implement.h" +/* + * Code contributed by John E. Bossom <JEB>. + */ + +int +pthread_setcancelstate (int state, int *oldstate) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function atomically sets the calling thread's +      *      cancelability state to 'state' and returns the previous +      *      cancelability state at the location referenced by +      *      'oldstate' +      * +      * PARAMETERS +      *      type, +      *      oldtype +      *              PTHREAD_CANCEL_ENABLE +      *                      cancellation is enabled, +      * +      *              PTHREAD_CANCEL_DISABLE +      *                      cancellation is disabled +      * +      * +      * DESCRIPTION +      *      This function atomically sets the calling thread's +      *      cancelability state to 'state' and returns the previous +      *      cancelability state at the location referenced by +      *      'oldstate' +      * +      *      NOTES: +      *      1)      Use to disable cancellation around 'atomic' code that +      *              includes cancellation points +      * +      * RESULTS +      *              0               successfully set cancelability type, +      *              EINVAL          'state' is invalid +      * +      * ------------------------------------------------------ +      */ +{ +  pthread_t self; +  int result; + +  if (((self = pthread_self ()) != NULL) && +      (state == PTHREAD_CANCEL_ENABLE || +       state == PTHREAD_CANCEL_DISABLE)) +    { + +      *oldstate = self->cancelState; +      self->cancelState = state; +      result = 0; + +    } +  else +    { +      result = EINVAL; +    } + +  return (result); + +}				/* pthread_setcancelstate */ + + +int +pthread_setcanceltype (int type, int *oldtype) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function atomically sets the calling thread's +      *      cancelability type to 'type' and returns the previous +      *      cancelability type at the location referenced by +      *      'oldtype' +      * +      * PARAMETERS +      *      type, +      *      oldtype +      *              PTHREAD_CANCEL_DEFERRED +      *                      only deferred cancelation is allowed, +      * +      *              PTHRAD_CANCEL_ASYNCHRONOUS +      *                      Asynchronous cancellation is allowed +      * +      * +      * DESCRIPTION +      *      This function atomically sets the calling thread's +      *      cancelability type to 'type' and returns the previous +      *      cancelability type at the location referenced by +      *      'oldtype' +      * +      *      NOTES: +      *      1)      Use with caution; most code is not safe for use +      *              with asynchronous cancelability. +      * +      * RESULTS +      *              0               successfully set cancelability type, +      *              EINVAL          'type' is invalid +      * +      * ------------------------------------------------------ +      */ +{ +  pthread_t self; +  int result; + +  if (((self = pthread_self ()) != NULL) && +      (type == PTHREAD_CANCEL_DEFERRED || +       type == PTHREAD_CANCEL_ASYNCHRONOUS)) +    { + +      *oldtype = self->cancelType; +      self->cancelType = type; +      result = 0; + +    } +  else +    { +      result = EINVAL; +    } + +  return (result); + +}				/* pthread_setcanceltype */ + +void +pthread_testcancel (void) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function creates a deferred cancellation point +      *      in the calling thread. The call has no effect if the +      *      current cancelability state is +      *              PTHREAD_CANCEL_DISABLE +      * +      * PARAMETERS +      *      N/A +      * +      * +      * DESCRIPTION +      *      This function creates a deferred cancellation point +      *      in the calling thread. The call has no effect if the +      *      current cancelability state is +      *              PTHREAD_CANCEL_DISABLE +      * +      *      NOTES: +      *      1)      Cancellation is asynchronous. Use pthread_join +      *              to wait for termination of thread if necessary +      * +      * RESULTS +      *              N/A +      * +      * ------------------------------------------------------ +      */ +{ +  pthread_t self; + +  if ((self = pthread_getspecific (_pthread_selfThreadKey)) != NULL) +    { + +      if (self->cancelState == PTHREAD_CANCEL_ENABLE) +	{ + +	  if (WaitForSingleObject (self->cancelEvent, 0) == +	      WAIT_OBJECT_0) +	    { +	      /* +	       * Canceling! +	       */ +	      DWORD exceptionInformation[3]; + +	      exceptionInformation[0] = (DWORD) (0); +	      exceptionInformation[1] = (DWORD) (0); + +	      RaiseException ( +			       EXCEPTION_PTHREAD_SERVICES, +			       0, +			       3, +			       exceptionInformation); +	    } +	} +    } + +}				/* pthread_testcancel */ + +int +pthread_cancel (pthread_t thread) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function requests cancellation of 'thread'. +      * +      * PARAMETERS +      *      thread +      *              reference to an instance of pthread_t +      * +      * +      * DESCRIPTION +      *      This function requests cancellation of 'thread'. +      *      NOTE: cancellation is asynchronous; use pthread_join to +      *                wait for termination of 'thread' if necessary. +      * +      * RESULTS +      *              0               successfully created semaphore, +      *              ESRCH           no thread found corresponding to 'thread', +      * +      * ------------------------------------------------------ +      */ +{ +  int result; + +  if (thread != NULL) +    { + +      if (!SetEvent (thread->cancelEvent)) +	{ +	  result = ESRCH; +	} +      else +	{ +	  result = 0; +	} + +    } +  else +    { +      result = ESRCH; +    } + +  return (result); +} + +/* </JEB> */ + +#if 0 /* Pre Bossom */ + +#include <errno.h> + +#include "pthread.h" +#include "implement.h" +  int  pthread_setcancelstate(int state,  		       int *oldstate) @@ -82,3 +321,5 @@ pthread_testcancel(void)      }    /* Never reached. */  } + +#endif /* Pre Bossom */ @@ -5,6 +5,709 @@   * This translation unit implements condition variables and their primitives.   */ +/* + * Code contributed by John E. Bossom <JEB>. + */ + +#include <errno.h> +#include <string.h> + +#include "pthread.h" +#include "implement.h" + +int +pthread_condattr_init (pthread_condattr_t * attr) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      Initializes a condition variable attributes object +      *      with default attributes. +      * +      * PARAMETERS +      *      attr +      *              pointer to an instance of pthread_condattr_t +      * +      * +      * DESCRIPTION +      *      Initializes a condition variable attributes object +      *      with default attributes. +      * +      *      NOTES: +      *              1)      Use to define condition variable types +      *              2)      It is up to the application to ensure +      *                      that it doesn't re-init an attribute +      *                      without destroying it first. Otherwise +      *                      a memory leak is created. +      * +      * RESULTS +      *              0               successfully initialized attr, +      *              ENOMEM          insufficient memory for attr. +      * +      * ------------------------------------------------------ +      */ +{ +  pthread_condattr_t attr_result; +  int result = 0; + +  attr_result = calloc (1, sizeof (*attr_result)); + +  if (attr_result == NULL) +    { +      result = ENOMEM; +    } + +  *attr = attr_result; + +  return (result); + +}                               /* pthread_condattr_init */ + + +int +pthread_condattr_destroy (pthread_condattr_t * attr) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      Destroys a condition variable attributes object. +      *      The object can no longer be used. +      * +      * PARAMETERS +      *      attr +      *              pointer to an instance of pthread_condattr_t +      * +      * +      * DESCRIPTION +      *      Destroys a condition variable attributes object. +      *      The object can no longer be used. +      * +      *      NOTES: +      *      1)      Does not affect condition variables created +      *              using 'attr' +      * +      * RESULTS +      *              0               successfully released attr, +      *              EINVAL          'attr' is invalid. +      * +      * ------------------------------------------------------ +      */ +{ +  int result = 0; + +  if (attr == NULL || *attr == NULL) +    { +      result = EINVAL; + +    } +  else +    { +      free (*attr); + +      *attr = NULL; +      result = 0; +    } + +  return (result); + +}                               /* pthread_condattr_destroy */ + + +int +pthread_condattr_getpshared (const pthread_condattr_t * attr, int *pshared) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      Determine whether condition variables created with 'attr' +      *      can be shared between processes. +      * +      * PARAMETERS +      *      attr +      *              pointer to an instance of pthread_condattr_t +      * +      *      pshared +      *              will be set to one of: +      * +      *                      PTHREAD_PROCESS_SHARED +      *                              May be shared if in shared memory +      * +      *                      PTHREAD_PROCESS_PRIVATE +      *                              Cannot be shared. +      * +      * +      * DESCRIPTION +      *      Condition Variables created with 'attr' can be shared +      *      between processes if pthread_cond_t variable is allocated +      *      in memory shared by these processes. +      *      NOTES: +      *      1)      pshared condition variables MUST be allocated in +      *              shared memory. +      * +      *      2)      The following macro is defined if shared mutexes +      *              are supported: +      *                      _POSIX_THREAD_PROCESS_SHARED +      * +      * RESULTS +      *              0               successfully retrieved attribute, +      *              EINVAL          'attr' is invalid, +      * +      * ------------------------------------------------------ +      */ +{ +  int result; + +  if ((attr != NULL && *attr != NULL) && +      (pshared != NULL)) +    { + +      *pshared = (*attr)->pshared; +      result = 0; + +    } +  else +    { +      *pshared = PTHREAD_PROCESS_PRIVATE; +      result = EINVAL; +    } + +  return (result); + +}                               /* pthread_condattr_getpshared */ + + +int +pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      Mutexes created with 'attr' can be shared between +      *      processes if pthread_mutex_t variable is allocated +      *      in memory shared by these processes. +      * +      * PARAMETERS +      *      attr +      *              pointer to an instance of pthread_mutexattr_t +      * +      *      pshared +      *              must be one of: +      * +      *                      PTHREAD_PROCESS_SHARED +      *                              May be shared if in shared memory +      * +      *                      PTHREAD_PROCESS_PRIVATE +      *                              Cannot be shared. +      * +      * DESCRIPTION +      *      Mutexes creatd with 'attr' can be shared between +      *      processes if pthread_mutex_t variable is allocated +      *      in memory shared by these processes. +      * +      *      NOTES: +      *              1)      pshared mutexes MUST be allocated in shared +      *                      memory. +      * +      *              2)      The following macro is defined if shared mutexes +      *                      are supported: +      *                              _POSIX_THREAD_PROCESS_SHARED +      * +      * RESULTS +      *              0               successfully set attribute, +      *              EINVAL          'attr' or pshared is invalid, +      *              ENOSYS          PTHREAD_PROCESS_SHARED not supported, +      * +      * ------------------------------------------------------ +      */ +{ +  int result; + +  if ((attr != NULL && *attr != NULL) && +      ((pshared == PTHREAD_PROCESS_SHARED) || +       (pshared == PTHREAD_PROCESS_PRIVATE))) +    { + + +      if (pshared == PTHREAD_PROCESS_SHARED) +        { + +#if !defined( _POSIX_THREAD_PROCESS_SHARED ) +          result = ENOSYS; +          pshared = PTHREAD_PROCESS_PRIVATE; +#else +          result = 0; + +#endif /* _POSIX_THREAD_PROCESS_SHARED */ + +        } +      else +        { +          result = 0; +        } +      (*attr)->pshared = pshared; + +    } +  else +    { +      result = EINVAL; + +    } + +  return (result); + +}                               /* pthread_condattr_setpshared */ + + +int +pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function initializes a condition variable. +      * +      * PARAMETERS +      *      cond +      *              pointer to an instance of pthread_cond_t +      * +      *      attr +      *              specifies optional creation attributes. +      * +      * +      * DESCRIPTION +      *      This function initializes a condition variable. +      * +      * RESULTS +      *              0               successfully created condition variable, +      *              EINVAL          'attr' is invalid, +      *              EAGAIN          insufficient resources (other than +      *                              memory, +      *              ENOMEM          insufficient memory, +      *              EBUSY           'cond' is already initialized, +      * +      * ------------------------------------------------------ +      */ +{ +  int result = EAGAIN; +  pthread_cond_t cv; + +  if ((attr != NULL && *attr != NULL) && +      ((*attr)->pshared == PTHREAD_PROCESS_SHARED)) +    { +      /* +       * Creating condition variable that can be shared between +       * processes. +       */ +      result = ENOSYS; + +      goto FAIL0; +    } + +  cv = (pthread_cond_t) calloc (1, sizeof (*cv)); + +  if (cv != NULL) +    { +      result = ENOMEM; +      goto FAIL0; +    } + +  cv->waiters = 0; +  cv->wasBroadcast = FALSE; + +  if (sem_init (&(cv->sema), 0, 1) != 0) +    { +      goto FAIL0; +    } +  if (pthread_mutex_init (&(cv->waitersLock), NULL) != 0) +    { +      goto FAIL1; +    } + +  cv->waitersDone = CreateEvent ( +                                  0, +                                  (int) FALSE,  /* manualReset  */ +                                  (int) FALSE,  /* setSignaled  */ +                                  NULL); + +  if (cv->waitersDone == NULL) +    { +      goto FAIL2; +    } + +  result = 0; + +  goto DONE; + +  /* +   * ------------- +   * Failure Code +   * ------------- +   */ +FAIL2: +  (void) pthread_mutex_destroy (&(cv->waitersLock)); + +FAIL1: +  (void) sem_destroy (&(cv->sema)); +  free (cv); +  cv = NULL; + +FAIL0: +DONE: +  *cond = cv; +  return (result); + +}                               /* pthread_cond_init */ + + +int +pthread_cond_destroy (pthread_cond_t * cond) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function destroys a condition variable +      * +      * +      * PARAMETERS +      *      cond +      *              pointer to an instance of pthread_cond_t +      * +      * +      * DESCRIPTION +      *      This function destroys a condition variable. +      * +      *      NOTES: +      *              1)      Safest after wakeup from 'cond', when +      *                      no other threads will wait. +      * +      * RESULTS +      *              0               successfully released condition variable, +      *              EINVAL          'cond' is invalid, +      *              EBUSY           'cond' is in use, +      * +      * ------------------------------------------------------ +      */ +{ +  int result = 0; +  pthread_cond_t cv; + +  if (cond != NULL && *cond != NULL) +    { +      cv = *cond; + +      (void) sem_destroy (&(cv->sema)); +      (void) pthread_mutex_destroy (&(cv->waitersLock)); +      (void) CloseHandle (cv->waitersDone); + +      free (cv); + +      *cond = NULL; +    } + +  return (result); +} + +int +pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function waits on a condition variable until +      *      awakened by a signal or broadcast. +      * +      *      Caller MUST be holding the mutex lock; the +      *      lock is released and the caller is blocked waiting +      *      on 'cond'. When 'cond' is signaled, the mutex +      *      is re-acquired before returning to the caller. +      * +      * PARAMETERS +      *      cond +      *              pointer to an instance of pthread_cond_t +      * +      *      mutex +      *              pointer to an instance of pthread_mutex_t +      * +      * +      * DESCRIPTION +      *      This function waits on a condition variable until +      *      awakened by a signal or broadcast. +      * +      *      NOTES: +      *      1)      The function must be called with 'mutex' LOCKED +      *               by the calling thread, or undefined behaviour +      *              will result. +      * +      *      2)      This routine atomically releases 'mutex' and causes +      *              the calling thread to block on the condition variable. +      *              The blocked thread may be awakened by  +      *                      pthread_cond_signal or  +      *                      pthread_cond_broadcast. +      * +      * Upon successful completion, the 'mutex' has been locked and  +      * is owned by the calling thread. +      * +      * RESULTS +      *              0               caught condition; mutex released, +      *              EINVAL          'cond' or 'mutex' is invalid, +      *              EINVAL          different mutexes for concurrent waits, +      *              EINVAL          mutex is not held by the calling thread, +      * +      * ------------------------------------------------------ +      */ +{ +  int result = 0; +  pthread_cond_t cv; +  int lastWaiter; + +  cv = *cond; + +  /* +   * OK to increment  cv->waiters because the caller locked 'mutex' +   * +   * FIXME: This is true. However, it is technically possible to call cond_wait +   * on this cv with a different mutex. The standard leaves the result of such an +   * action as undefined. (RPJ) +   */ +  cv->waiters++; + +  /* +   * We keep the lock held just long enough to increment the count of +   * waiters by one (above). +   * Note that we can't keep it held across the +   * call to sem_wait since that will deadlock other calls +   * to pthread_cond_signal +   */ +  if ((result = pthread_mutex_unlock (mutex)) == 0) +    { +      /* +       * Wait to be awakened by +       *              pthread_cond_signal, or +       *              pthread_cond_broadcast +       * +       * Note:  +       *      sem_wait is a cancellation point, hence providing the +       *      mechanism for making pthread_cond_wait a cancellation +       *      point. We use the cleanup mechanism to ensure we +       *  re-lock the mutex if we are cancelled. +       */ +      pthread_cleanup_push (pthread_mutex_lock, mutex); + +      result = sem_wait (&(cv->sema)); + +      pthread_cleanup_pop (0); +    } + +  if ((result = pthread_mutex_lock (&(cv->waitersLock))) == 0) +    { +      /* +       * By making the waiter responsible for decrementing +       * its count we don't have to worry about having an internal +       * mutex. +       */ +      cv->waiters--; + +      lastWaiter = cv->wasBroadcast && (cv->waiters == 0); + +      result = pthread_mutex_unlock (&(cv->waitersLock)); +    } + +  if (result == 0) +    { +      if (lastWaiter) +        { +          /* +           * If we are the last waiter on this broadcast +           * let the thread doing the broadcast proceed +           */ +          if (!SetEvent (cv->waitersDone)) +            { +              result = EINVAL; +            } +        } +    } + +  /* +   * We must always regain the external mutex, even when +   * errors occur because that's the guarantee that we give +   * to our callers +   */ +  (void) pthread_mutex_lock (mutex); + + +  return (result); + +}                               /* pthread_cond_wait */ + + +int +pthread_cond_timedwait (pthread_cond_t * cond, +                         pthread_mutex_t * mutex, +                         const struct timespec *abstime) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function initializes an unnamed semaphore. the +      *      initial value of the semaphore is 'value' +      * +      * PARAMETERS +      *      sem +      *              pointer to an instance of sem_t +      * +      * +      * DESCRIPTION +      *      This function  initializes an unnamed semaphore. The +      *      initial value of the semaphore is set to 'value'. +      * +      * RESULTS +      *              0               successfully created semaphore, +      *              EINVAL          'sem' is not a valid semaphore, +      *              ENOSPC          a required resource has been exhausted, +      *              ENOSYS          semaphores are not supported, +      *              EPERM           the process lacks appropriate privilege +      * +      * ------------------------------------------------------ +      */ +{ +  int result = 0; +  /* +   * NOT IMPLEMENTED YET!!! +   */ +  return (result); +} + + +int +pthread_cond_signal (pthread_cond_t * cond) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function signals a condition variable, waking +      *      one waiting thread. +      *      If SCHED_FIFO or SCHED_RR policy threads are waiting +      *      the highest priority waiter is awakened; otherwise, +      *      an unspecified waiter is awakened. +      * +      * PARAMETERS +      *      cond +      *              pointer to an instance of pthread_cond_t +      * +      * +      * DESCRIPTION +      *      This function signals a condition variable, waking +      *      one waiting thread. +      *      If SCHED_FIFO or SCHED_RR policy threads are waiting +      *      the highest priority waiter is awakened; otherwise, +      *      an unspecified waiter is awakened. +      * +      *      NOTES: +      *      1)      Use when any waiter can respond and only one need +      *              respond (all waiters being equal). +      * +      *      2)      This function MUST be called under the protection  +      *              of the SAME mutex that is used with the condition +      *              variable being signaled; OTHERWISE, the condition +      *              variable may be signaled between the test of the +      *              associated condition and the blocking +      *              pthread_cond_signal. +      *              This can cause an infinite wait. +      * +      * RESULTS +      *              0               successfully signaled condition, +      *              EINVAL          'cond' is invalid, +      * +      * ------------------------------------------------------ +      */ +{ +  int result = 0; +  pthread_cond_t cv = *cond; + +  /* +   * If there aren't any waiters, then this is a no-op. +   */ +  if (cv->waiters > 0) +    { + +      result = sem_post (&(cv->sema)); +    } + +  return (result); + +}                               /* pthread_cond_signal */ + +int +pthread_cond_broadcast (pthread_cond_t * cond) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function broadcasts the condition variable, +      *      waking all current waiters. +      * +      * PARAMETERS +      *      sem +      *              pointer to an instance of pthread_cond_t +      * +      * +      * DESCRIPTION +      *      This function  initializes an unnamed semaphore. The +      *      initial value of the semaphore is set to 'value'. +      * +      *      NOTES: +      *      1)      This function MUST be called under the protection +      *              of the SAME mutex that is used with the condition +      *              variable being signaled; OTHERWISE, the condition +      *              variable may be signaled between the test of the +      *              associated condition and the blocking pthread_cond_wait. +      *              This can cause an infinite wait. +      * +      *      2)      Use when more than one waiter may respond to +      *              predicate change or if any waiting thread may +      *              not be able to respond +      * +      * RESULTS +      *              0               successfully created semaphore, +      *              EINVAL          'cond' is invalid +      *              ENOSPC          a required resource has been exhausted, +      * +      * ------------------------------------------------------ +      */ +{ +  int result = 0; +  pthread_cond_t cv = *cond; +  int i; + +  cv->wasBroadcast = TRUE; + +  /* +   * Wake up all waiters +   */ +  for (i = cv->waiters; i > 0 && result == 0; i--) +    { + +      result = sem_post (&(cv->sema)); +    } + +  if (result == 0) +    { +      /* +       * Wait for all the awakened threads to acquire their part of +       * the counting semaphore +       */ +      if (WaitForSingleObject (cv->waitersDone, INFINITE) != +          WAIT_OBJECT_0) +        { + +          result = 0; + +        } +      else +        { +          result = EINVAL; +        } + +    } + +  return (result); +} + +/* </JEB> */ + + +#if 0 /* Pre Bossom */ +  #include <errno.h>  #include <windows.h> @@ -202,3 +905,5 @@ pthread_cond_destroy(pthread_cond_t *cv)    return pthread_mutex_destroy(&cv->waiters_count_lock);  } + +#endif /* Pre Bossom */ @@ -6,6 +6,149 @@   * thread.   */ +#include "pthread.h" +#include "implement.h" + +/* + * Code contributed by John E. Bossom <JEB>. + */ + +int +pthread_create (pthread_t * tid, +		const pthread_attr_t * attr, +		void *(*start) (void *), +		void *arg) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function creates a thread running the start function, +      *      passing it the parameter value, 'arg'. +      * +      * PARAMETERS +      *      tid +      *              pointer to an instance of pthread_t +      * +      *      attr +      *              optional pointer to an instance of pthread_attr_t +      * +      *      start +      *              pointer to the starting routine for the new thread +      * +      *      arg +      *              optional parameter passed to 'start' +      * +      * +      * DESCRIPTION +      *      This function creates a thread running the start function, +      *      passing it the parameter value, 'arg'. The 'attr' +      *      argument specifies optional creation attributes. +      *      The thread is identity of the new thread is returned +      *      as 'tid' +      * +      * RESULTS +      *              0               successfully created thread, +      *              EINVAL          attr invalid, +      *              EAGAIN          insufficient resources. +      * +      * ------------------------------------------------------ +      */ +{ +  pthread_t thread; +  int result = EAGAIN; +  int run = TRUE; +  ThreadParms *parms; +  long stackSize; + +  if ((thread = (pthread_t) calloc (1, sizeof (*thread))) == +      NULL) +    { +      goto FAIL0; +    } +  thread->cancelEvent = +    CreateEvent ( +		  0, +		  (int) TRUE,	/* manualReset  */ +		  (int) FALSE,	/* setSignaled  */ +		  NULL); + +  if (thread->cancelEvent == NULL) +    { +      goto FAIL0; +    } + +  if ((parms = (ThreadParms *) malloc (sizeof (*parms))) == +      NULL) +    { +      goto FAIL0; +    } + +  parms->tid = thread; +  parms->start = start; +  parms->arg = arg; + +  if (attr != NULL && *attr != NULL) +    { +      stackSize = (*attr)->stacksize; +      thread->detachState = (*attr)->detachstate; + +    } +  else +    { +      /* +       * Default stackSize +       */ +      stackSize = 0; +    } + +  thread->state = run +    ? PThreadStateInitial +    : PThreadStateSuspended; + +  thread->keys = NULL; +  thread->threadH = (HANDLE) +    _beginthreadex ( +		     (void *) NULL,	/* No security info             */ +		     (unsigned) stackSize,	/* default stack size   */ +		     (unsigned (__stdcall *) (void *)) threadStart, +		     parms, +		     (unsigned) run ? 0 : CREATE_SUSPENDED, +		     (unsigned *) &(thread->thread)); + +  result = (thread->threadH != 0) ? 0 : EAGAIN; + +  /* +   * Fall Through Intentionally +   */ + +  /* +   * ------------ +   * Failure Code +   * ------------ +   */ + +FAIL0: +  if (result != 0) +    { + +      threadDestroy (thread); +      thread = NULL; + +      if (parms != NULL) +	{ +	  free (parms); +	} +    } +  *tid = thread; + +  return (result); + +}				/* pthread_create */ + +/* </JEB> */ + + +#if 0 /* Pre Bossom */ +  #include <errno.h>  #include <windows.h> @@ -146,5 +289,4 @@ pthread_create(pthread_t *thread,    return ret;  } - - +#endif /* Pre Bossom */ @@ -5,6 +5,112 @@   * This translation unit implements DLL initialisation.   */ +#include <windows.h> +#include <malloc.h> +#include "pthread.h" +#include "implement.h" + + +/* Function pointer to TryEnterCriticalSection if it exists; otherwise NULL */ +BOOL (WINAPI *_pthread_try_enter_critical_section)(LPCRITICAL_SECTION) = NULL; + +/* Handle to kernel32.dll */ +static HINSTANCE _pthread_h_kernel32; + +#ifdef _WIN32 +/*  + * lpvReserved yields an unreferenced formal parameter; + * ignore it + */ +#pragma warning( disable : 4100 ) +#endif + +BOOL WINAPI +DllMain ( +	  HINSTANCE hinstDll, +	  DWORD fdwReason, +	  LPVOID lpvReserved +) +{ +  BOOL result = TRUE; + +  switch (fdwReason) +    { + +    case DLL_PROCESS_ATTACH: +      /* +       * The DLL is being mapped into the process's address space +       */ +      result = _pthread_processInitialize (); + +      /* Load KERNEL32 and try to get address of TryEnterCriticalSection */ +      _pthread_h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL")); +      _pthread_try_enter_critical_section = +	(void *) GetProcAddress(_pthread_h_kernel32, +				"TryEnterCriticalSection"); +      break; + +    case DLL_THREAD_ATTACH: +      /* +       * A thread is being created +       */ +      result = TRUE; +      break; + +    case DLL_THREAD_DETACH: +    case DLL_PROCESS_DETACH: +      /* +       * A thread is exiting cleanly +       * NOTE: The "main" thread detaches using +       *               DLL_PROCESS_DETACH +       */ +      { +	pthread_t self; + +	if (_pthread_processInitialized) +	  { +#if defined( KLUDGE ) +	    _pthread_cleanupStack (); +#endif /* KLUDGE */ + +	    self = (pthread_t) pthread_getspecific (_pthread_selfThreadKey); + +	    /* +	     * Detached threads have their resources automatically +	     * cleaned up upon exit (others must be 'joined' +	     */ +	    if (self != NULL && +		self->detachState == PTHREAD_CREATE_DETACHED) +	      { + +		pthread_setspecific (_pthread_selfThreadKey, NULL); + +		_pthread_threadDestroy (self); +	      } + +	    if (fdwReason == DLL_PROCESS_DETACH) +	      { +		/* +		 * The DLL is being unmapped into the process's address space +		 */ +		_pthread_processTerminate (); +	      } +	  } + +	(void) FreeLibrary(_pthread_h_kernel32); + +	result = TRUE; +      } +      break; +    } +  return (result); + +}				/* DllMain */ + + + +#if 0 /* Pre Bossom */ +  /* We use the DLL entry point function to set up per thread storage     specifically to hold the threads own thread ID. @@ -14,11 +120,6 @@   */ -#include <windows.h> -#include <malloc.h> -#include "pthread.h" -#include "implement.h" -  /* Global index for TLS data. */  DWORD _pthread_threadID_TlsIndex; @@ -78,3 +179,5 @@ BOOL WINAPI PthreadsEntryPoint(HINSTANCE dllHandle,    return TRUE;  } + +#endif /* Pre Bossom */ @@ -11,6 +11,47 @@  #include "pthread.h"  #include "implement.h" +/* + * Code contributed by John E. Bossom <JEB>. + */ + +int +pthread_exit (void *value_ptr) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function terminates the calling thread, returning +      *      the value 'value_ptr' to any joining thread. +      * +      * PARAMETERS +      *      value_ptr +      *              a generic data value (i.e. not the address of a value) +      * +      * +      * DESCRIPTION +      *      This function terminates the calling thread, returning +      *      the value 'value_ptr' to any joining thread. +      *      NOTE: thread should be joinable. +      * +      * RESULTS +      *              N/A +      * +      * ------------------------------------------------------ +      */ +{ +  _pthread_callUserDestroyRoutines(pthread_getspecific(_pthread_selfThreadKey)); + +  _endthreadex ((unsigned) value_ptr); + +  return (0); + +}				/* pthread_exit */ + +/* </JEB> */ + + +#if 0 /* Pre Bossom */ +  void  _pthread_vacuum(void)  { @@ -72,3 +113,5 @@ pthread_exit(void * value)  {    _pthread_exit(pthread_self(), value, 0);  } + +#endif /* Pre Bossom */ @@ -11,6 +11,14 @@  #include "pthread.h"  #include "implement.h" + +int _pthread_processInitialized = FALSE; +pthread_key_t _pthread_selfThreadKey = NULL; +pthread_key_t _pthread_cleanupKey = NULL; + + +#if 0 /* Pre Bossom */ +  /* POSIX run-time invariant values. (Currently POSIX minimum values)     Making these constants will mean that applications remain binary @@ -81,3 +89,5 @@ pthread_key_t _pthread_key_reuse[_PTHREAD_MAX_KEYS];  /* Index to the first available reusable pthread_key_t. */  int _pthread_key_reuse_top; + +#endif /* Pre Bossom */ diff --git a/implement.h b/implement.h index db6b5a2..523f475 100644 --- a/implement.h +++ b/implement.h @@ -1,12 +1,281 @@  /*   * implement.h   * - * Implementation specific (non API) stuff. + * Definitions that don't need to be public. + * + * Keeps all the internals out of pthread.h   */  #ifndef _IMPLEMENT_H  #define _IMPLEMENT_H +/* + * Code contributed by John E. Bossom <JEB>. + */ + +typedef enum { +  /* +   * This enumeration represents the state of the thread; +   * The thread is still "alive" if the numeric value of the +   * state is greater or equal "PThreadStateRunning". +   */ +  PThreadStateInitial = 0,	/* Thread not running                   */ +  PThreadStateRunning,	        /* Thread alive & kicking               */ +  PThreadStateSuspended,	/* Thread alive but suspended           */ +  PThreadStateCanceling,	/* Thread alive but and is              */ +                                /* in the process of terminating        */ +                                /* due to a cancellation request        */ +  PThreadStateException,	/* Thread alive but exiting             */ +                                /* due to an exception                  */ +  PThreadStateLast +} +PThreadState; + + +typedef enum { +  /* +   * This enumeration represents the reason why a thread has +   * terminated/is terminating. +   */ +  PThreadDemisePeaceful = 0,	/* Death due natural causes     */ +  PThreadDemiseCancelled,	/* Death due to user cancel     */ +  PThreadDemiseException,	/* Death due to unhandled       */ +                                /* exception                    */ +  PThreadDemiseNotDead	/* I'm not dead!                */ +} +PThreadDemise; + + +struct pthread_t_ { +  DWORD thread; +  HANDLE threadH; +  PThreadState state; +  PThreadDemise demise; +  void *exitStatus; +  void *parms; +  int detachState; +  int cancelState; +  int cancelType; +  HANDLE cancelEvent; +  int implicit:1; +  void *keys; +}; + + +struct pthread_attr_t_ { +  void *stackaddr; +  size_t stacksize; +  int detachstate; +}; + + +struct pthread_key_t_ { +  DWORD key; +  void (*destructor) (void *); +  pthread_mutex_t threadsLock; +  void *threads; +}; + + +struct pthread_mutexattr_t_ { +  int pshared; +}; + + +struct pthread_mutex_t_ { +	int valid; +	CRITICAL_SECTION cs; +  }; + + +struct pthread_cond_t_ { +  long waiters;                       /* # waiting threads             */ +  pthread_mutex_t waitersLock;        /* Mutex that guards access to  +					 waiter count                  */ +  sem_t sema;                         /* Queue up threads waiting for the  +					 condition to become signaled  */ +  HANDLE waitersDone;                 /* An auto reset event used by the  +					 broadcast/signal thread to wait  +					 for the waiting thread(s) to wake +					 up and get a chance at the   +					 semaphore                     */ +  int wasBroadcast;                   /* keeps track if we are signaling  +					 or broadcasting               */ +}; + + +struct pthread_condattr_t_ { +  int pshared; +}; + + +struct pthread_once_t_ { +  unsigned short flag; +  pthread_mutex_t lock; +}; + + +typedef struct ThreadParms ThreadParms; +typedef struct ThreadKeyAssoc ThreadKeyAssoc; + + +struct ThreadParms { +  pthread_t tid; +  void *(*start) (void *); +  void *arg; +}; + + +struct ThreadKeyAssoc { +  /* +   * Purpose: +   *      This structure creates an association between a +   *      thread and a key. +   *      It is used to implement the implicit invocation +   *      of a user defined destroy routine for thread +   *      specific data registered by a user upon exiting a +   *      thread. +   * +   * Attributes: +   *      lock +   *              protects access to the rest of the structure +   * +   *      thread +   *              reference to the thread that owns the association. +   *              As long as this is not NULL, the association remains +   *              referenced by the pthread_t. +   * +   *      key +   *              reference to the key that owns the association. +   *              As long as this is not NULL, the association remains +   *              referenced by the pthread_key_t. +   * +   *      nextKey +   *              The pthread_t->keys attribute is the head of a +   *              chain of associations that runs through the nextKey +   *              link. This chain provides the 1 to many relationship +   *              between a pthread_t and all pthread_key_t on which +   *              it called pthread_setspecific. +   * +   *      nextThread +   *              The pthread_key_t->threads attribute is the head of +   *              a chain of assoctiations that runs through the +   *              nextThreads link. This chain provides the 1 to many +   *              relationship between a pthread_key_t and all the  +   *              PThreads that have called pthread_setspecific for +   *              this pthread_key_t. +   * +   * +   * Notes: +   *      1)      As long as one of the attributes, thread or key, is +   *              not NULL, the association is being referenced; once +   *              both are NULL, the association must be released. +   * +   *      2)      Under WIN32, an association is only created by +   *              pthread_setspecific if the user provided a +   *              destroyRoutine when they created the key. +   * +   * +   */ +  pthread_mutex_t lock; +  pthread_t thread; +  pthread_key_t key; +  ThreadKeyAssoc *nextKey; +  ThreadKeyAssoc *nextThread; +}; + + +/* + * -------------------------------------------------------------- + * MAKE_SOFTWARE_EXCEPTION + *      This macro constructs a software exception code following + *      the same format as the standard Win32 error codes as defined + *      in WINERROR.H + *  Values are 32 bit values layed out as follows: + * + *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + *  +---+-+-+-----------------------+-------------------------------+ + *  |Sev|C|R|     Facility          |               Code            | + *  +---+-+-+-----------------------+-------------------------------+ + * + * Severity Values: + */ +#define SE_SUCCESS              0x00 +#define SE_INFORMATION	        0x01 +#define SE_WARNING              0x10 +#define SE_ERROR                0x11 + +#define MAKE_SOFTWARE_EXCEPTION( _severity, _facility, _exception ) \ +( (DWORD) ( ( (_severity) << 30 ) |	/* Severity code	*/ \ +	    ( 1 << 29 )	|		/* MS=0, User=1		*/ \ +	    ( 0 << 28 )	|		/* Reserved		*/ \ +	    ( (_facility) << 16 ) |	/* Facility Code	*/ \ +	    ( (_exception) <<  0 )	/* Exception Code	*/ \ +	    ) ) + +/* + * We choose one specific Facility/Error code combination to + * identify our software exceptions vs. WIN32 exceptions. + * We store our actual component and error code within + * the optional information array. + */ +#define EXCEPTION_PTHREAD_SERVICES	\ +     MAKE_SOFTWARE_EXCEPTION( SE_ERROR, \ +			      PTHREAD_SERVICES_FACILITY, \ +			      PTHREAD_SERVICES_ERROR ) + + +#define PTHREAD_SERVICES_FACILITY		0xBAD +#define PTHREAD_SERVICES_ERROR			0xDEED + + +/* Function pointer to TryEnterCriticalSection if it exists; otherwise NULL */ +extern BOOL (WINAPI *_pthread_try_enter_critical_section)(LPCRITICAL_SECTION); + +/* Declared in global.c */ +extern int _pthread_processInitialized; +extern pthread_key_t _pthread_selfThreadKey; +extern pthread_key_t _pthread_cleanupKey; + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * ===================== + * ===================== + * Forward Declarations + * ===================== + * ===================== + */ +int _pthread_processInitialize (void); + +void _pthread_processTerminate (void); + +void _pthread_threadDestroy (pthread_t tid); + +void _pthread_cleanupStack (void); + +void *_pthread_threadStart (ThreadParms * threadParms); + +void _pthread_callUserDestroyRoutines (pthread_t thread); + +int _pthread_tkAssocCreate (ThreadKeyAssoc ** assocP, +			    pthread_t thread, +			    pthread_key_t key); + +void _pthread_tkAssocDestroy (ThreadKeyAssoc * assoc); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/* </JEB> */ + + +#if 0 /* Pre Bossom */ +  /* Use internally to initialise const ints and thread admin array sizes. */  #define _PTHREAD_MAX_THREADS 128  #define _PTHREAD_MAX_KEYS 128 @@ -194,4 +463,6 @@ extern pthread_key_t _pthread_key_reuse[];  /* Index to the first available reusable pthread_key_t. */  extern int _pthread_key_reuse_top; +#endif /* Pre Bossom */ +  #endif /* _IMPLEMENT_H */ @@ -39,6 +39,214 @@ pthread_once(pthread_once_t *once_control,    return 0;  } +/* + * Code contributed by John E. Bossom <JEB>. + */ + +pthread_t +pthread_self (void) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function returns a reference to the current running +      *      thread. +      * +      * PARAMETERS +      *      N/A +      * +      * +      * DESCRIPTION +      *      This function returns a reference to the current running +      *      thread. +      * +      * RESULTS +      *              pthread_t       reference to the current thread +      * +      * ------------------------------------------------------ +      */ +{ +  pthread_t self = NULL; +  /* +   * need to ensure there always is a self +   */ + +  if ((self = pthread_getspecific (_pthread_selfThreadKey)) == NULL) +    { +      /* +       * Need to create an implicit 'self' for the currently +       * executing thread. +       */ +      self = (pthread_t) calloc (1, sizeof (*self)); +      if (self != NULL) +	{ + +	  self->implicit = 1; +	  self->detachState = PTHREAD_CREATE_DETACHED; + +	  self->thread = GetCurrentThreadId (); +	  self->threadH = GetCurrentThread (); +	} + +      pthread_setspecific (_pthread_selfThreadKey, self); +    } + +  return (self); + +}				/* pthread_self */ + +int +pthread_equal (pthread_t t1, pthread_t t2) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function returns zero if t1 and t2 are equal, else +      *      returns nonzero +      * +      * PARAMETERS +      *      t1, +      *      t2 +      *              references to an instances of thread_t +      * +      * +      * DESCRIPTION +      *      This function returns zero if t1 and t2 are equal, else +      *      returns nonzero. +      * +      * RESULTS +      *              0               if t1 and t2 refer to the same thread, +      *              non-zero        t1 and t2 do not refer to the same thread +      * +      * ------------------------------------------------------ +      */ +{ +  int result; + +  result = !((t1 == t2) || (t1->thread == t2->thread)); + +  return (result); + +}				/* pthread_equal */ + + +int +pthreadCancelableWait (HANDLE waitHandle) +     /* +      * ------------------------------------------------------------------- +      * This provides an extra hook into the pthread_cancel +      * mechanism that will allow you to wait on a Windows handle and make it a +      * cancellation point. This function blocks until the given WIN32 handle is +      * signaled or pthread_cancel has been called. It is implemented using +      * WaitForMultipleObjects on 'waitHandle' and a manually reset WIN32 +      * event used to implement pthread_cancel. +      *  +      * Given this hook it would be possible to implement more of the cancellation +      * points. +      * ------------------------------------------------------------------- +      */ +{ +  int result; +  pthread_t self; +  HANDLE handles[2]; +  DWORD nHandles = 1; +  DWORD status; + + +  handles[0] = waitHandle; + +  if ((self = pthread_getspecific (_pthread_selfThreadKey)) != NULL) +    { +      /* +       * Get cancelEvent handle +       */ +      if (self->cancelState == PTHREAD_CANCEL_ENABLE) +        { + +          if ((handles[1] = self->cancelEvent) != NULL) +            { +              nHandles++; +            } +        } +    } +  else +    { +      handles[1] = NULL; +    } + +  status = WaitForMultipleObjects ( +                                    nHandles, +                                    handles, +                                    FALSE, +                                    INFINITE); + + +  if (status == WAIT_FAILED) +    { +      result = EINVAL; + +    } +  else if (status == WAIT_ABANDONED_0) +    { +      result = EINVAL; + +    } +  else +    { +      /* +       * Either got the mutex or the cancel event +       * was signaled +       */ +      switch (status - WAIT_OBJECT_0) +        { + +        case 0: +          /* +           * Got the mutex +           */ +          result = 0; +          break; + +        case 1: +          /* +           * Got cancel request +           */ +          ResetEvent (handles[1]); + +          if (self != NULL && !self->implicit) +            { +              /* +               * Thread started with pthread_create +               */ +              DWORD exceptionInformation[3]; + +              exceptionInformation[0] = (DWORD) (0); +              exceptionInformation[1] = (DWORD) (0); + +              RaiseException ( +                               EXCEPTION_PTHREAD_SERVICES, +                               0, +                               3, +                               exceptionInformation); +            } + + +          ((void *) -1); +          break; + +        default: +          result = EINVAL; +          break; +        } +    } + +  return (result); + +}                               /* pthreadCancelableWait */ + + +/* </JEB> */ + +#if 0 /* Pre Bossom */ +  pthread_t  pthread_self(void)  { @@ -61,3 +269,5 @@ pthread_equal(pthread_t t1, pthread_t t2)  {    return (t1 == t2);  } + +#endif /* Pre Bossom */ @@ -11,6 +11,415 @@  #include "pthread.h"  #include "implement.h" +/* + * Code contributed by John E. Bossom <JEB>. + */ + +int +_pthread_processInitialize (void) +     /* +      * ------------------------------------------------------ +      * DOCPRIVATE +      *      This function performs process wide initialization for +      *      the pthread library. +      * +      * PARAMETERS +      *      N/A +      * +      * DESCRIPTION +      *      This function performs process wide initialization for +      *      the pthread library. +      *      If successful, this routine sets the global variable +      *      _pthread_processInitialized to TRUE. +      * +      * RESULTS +      *              TRUE    if successful, +      *              FALSE   otherwise +      * +      * ------------------------------------------------------ +      */ +{ +  _pthread_processInitialized = TRUE; + +  /* +   * Initialize Keys +   */ +  if ((pthread_key_create (&_pthread_selfThreadKey, NULL) != 0) || +      (pthread_key_create (&_pthread_cleanupKey, NULL) != 0)) +    { + +      _pthread_processTerminate (); +    } + +  return (_pthread_processInitialized); + +}				/* processInitialize */ + +void +_pthread_processTerminate (void) +     /* +      * ------------------------------------------------------ +      * DOCPRIVATE +      *      This function performs process wide termination for +      *      the pthread library. +      * +      * PARAMETERS +      *      N/A +      * +      * DESCRIPTION +      *      This function performs process wide termination for +      *      the pthread library. +      *      This routine sets the global variable +      *      _pthread_processInitialized to FALSE +      * +      * RESULTS +      *              N/A +      * +      * ------------------------------------------------------ +      */ +{ +  if (_pthread_processInitialized) +    { + +      if (_pthread_selfThreadKey != NULL) +	{ +	  /* +	   * Release _pthread_selfThreadKey +	   */ +	  pthread_key_delete (_pthread_selfThreadKey); + +	  _pthread_selfThreadKey = NULL; +	} + +      if (_pthread_cleanupKey != NULL) +	{ +	  /* +	   * Release _pthread_cleanupKey +	   */ +	  pthread_key_delete (_pthread_cleanupKey); + +	  _pthread_cleanupKey = NULL; +	} + +      _pthread_processInitialized = FALSE; +    } + +}				/* processTerminate */ + + + +void * +_pthread_threadStart (ThreadParms * threadParms) +{ +  pthread_t tid; +  void *(*start) (void *); +  void *arg; + +  int status; + +  tid = threadParms->tid; +  start = threadParms->start; +  arg = threadParms->arg; + +  free (threadParms); + +  pthread_setspecific (_pthread_selfThreadKey, tid); + +  __try +  { +    /* +     * Run the caller's routine; +     */ +    (*start) (arg); +    status = 0; +  } +  __except (EXCEPTION_EXECUTE_HANDLER) +  { +    /* +     * A system unexpected exception had occurred running the user's +     * routine. We get control back within this block. +     */ +    status = -1; +  } + +  pthread_exit ((void *) status); + +  return ((void *) status); + +}				/* threadStart */ + + +void +_pthread_threadDestroy (pthread_t thread) +{ +  if (thread != NULL) +    { + +      callUserDestroyRoutines (thread); + +      if (thread->cancelEvent != NULL) +	{ +	  CloseHandle (thread->cancelEvent); +	} + +      free (thread); +    } + +}				/* threadDestroy */ + +#if defined( KLUDGE ) + +void +_pthread_cleanupStack (void) +{ +  while (pthread_pop_cleanup (1)) +    { +    } + +}				/* cleanupStack */ + +#endif /* KLUDGE */ + +int +_pthread_tkAssocCreate (ThreadKeyAssoc ** assocP, +			pthread_t thread, +			pthread_key_t key) +     /* +      * ------------------------------------------------------------------- +      * This routine creates an association that +      * is unique for the given (thread,key) combination.The association  +      * is referenced by both the thread and the key. +      * This association allows us to determine what keys the +      * current thread references and what threads a given key +      * references. +      * See the detailed description +      * at the beginning of this file for further details. +      * +      * Notes: +      *      1)      New associations are pushed to the beginning of the +      *              chain so that the internal _pthread_selfThreadKey association +      *              is always last, thus allowing selfThreadExit to +      *              be implicitly called by pthread_exit last. +      * +      * Parameters: +      *              assocP +      *                      address into which the association is returned. +      *              thread +      *                      current running thread. If NULL, then association +      *                      is only added to the key. A NULL thread indicates +      *                      that the user called pthread_setspecific prior +      *                      to starting a thread. That's ok. +      *              key +      *                      key on which to create an association. +      * Returns: +      *       0              - if successful, +      *      -1              - general error +      * ------------------------------------------------------------------- +      */ +{ +  int result; +  ThreadKeyAssoc *assoc; + +  /* +   * Have to create an association and add it +   * to both the key and the thread. +   */ +  assoc = (ThreadKeyAssoc *) +    calloc (1, sizeof (*assoc)); + +  if (assoc == NULL) +    { +      result = -1; +      goto FAIL0; +    } + +  if ((result = pthread_mutex_init (&(assoc->lock), NULL)) != +      0) +    { +      goto FAIL1; +    } + +  assoc->thread = thread; +  assoc->key = key; + +  /* +   * Register assoc with key +   */ +  if ((result = pthread_mutex_lock (&(key->threadsLock))) != +      0) +    { +      goto FAIL2; +    } + +  assoc->nextThread = (ThreadKeyAssoc *) key->threads; +  key->threads = (void *) assoc; + +  pthread_mutex_unlock (&(key->threadsLock)); + +  if (thread != NULL) +    { +      /* +       * Register assoc with thread +       */ +      assoc->nextKey = (ThreadKeyAssoc *) thread->keys; +      thread->keys = (void *) assoc; +    } + +  *assocP = assoc; + +  return (result); + +  /* +   * ------------- +   * Failure Code +   * ------------- +   */ +FAIL2: +  pthread_mutex_destroy (&(assoc->lock)); + +FAIL1: +  free (assoc); + +FAIL0: + +  return (result); + +}				/* tkAssocCreate */ + + +void +_pthread_tkAssocDestroy (ThreadKeyAssoc * assoc) +     /* +      * ------------------------------------------------------------------- +      * This routine releases all resources for the given ThreadKeyAssoc +      * once it is no longer being referenced +      * ie) both the key and thread have stopped referencing it. +      * +      * Parameters: +      *              assoc +      *                      an instance of ThreadKeyAssoc. +      * Returns: +      *      N/A +      * ------------------------------------------------------------------- +      */ +{ + +  if ((assoc != NULL) && +      (assoc->key == NULL && assoc->thread == NULL)) +    { + +      pthread_mutex_destroy (&(assoc->lock)); + +      free (assoc); +    } + +}				/* tkAssocDestroy */ + + +void +_pthread_callUserDestroyRoutines (pthread_t thread) +     /* +      * ------------------------------------------------------------------- +      * DOCPRIVATE +      * +      * This the routine runs through all thread keys and calls +      * the destroy routines on the user's data for the current thread. +      * It simulates the behaviour of POSIX Threads. +      * +      * PARAMETERS +      *              thread +      *                      an instance of pthread_t +      * +      * RETURNS +      *              N/A +      * ------------------------------------------------------------------- +      */ +{ +  ThreadKeyAssoc **nextP; +  ThreadKeyAssoc *assoc; + +  if (thread != NULL) +    { +      /* +       * Run through all Thread<-->Key associations +       * for the current thread. +       * If the pthread_key_t still exits (ie the assoc->key +       * is not NULL) then call the user's TSD destroy routine. +       * Notes: +       *      If assoc->key is NULL, then the user previously called +       *      PThreadKeyDestroy. The association is now only referenced +       *      by the current thread and must be released; otherwise +       *      the assoc will be destroyed when the key is destroyed. +       */ +      nextP = (ThreadKeyAssoc **) & (thread->keys); +      assoc = *nextP; + +      while (assoc != NULL) +	{ + +	  if (pthread_mutex_lock (&(assoc->lock)) == 0) +	    { +	      pthread_key_t k; +	      if ((k = assoc->key) != NULL) +		{ +		  /* +		   * Key still active; pthread_key_delete +		   * will block on this same mutex before +		   * it can release actual key; therefore, +		   * key is valid and we can call the destroy +		   * routine; +		   */ +		  void *value = NULL; + +		  value = pthread_getspecific (k); +		  if (value != NULL && k->destructor != NULL) +		    { + +		      __try +		      { +			/* +			 * Run the caller's cleanup routine. +			 */ +			(*(k->destructor)) (value); +		      } +		      __except (EXCEPTION_EXECUTE_HANDLER) +		      { +			/* +			 * A system unexpected exception had occurred +			 * running the user's destructor. +			 * We get control back within this block. +			 */ +		      } +		    } +		} + +	      /* +	       * mark assoc->thread as NULL to indicate the +	       * thread no longer references this association +	       */ +	      assoc->thread = NULL; + +	      /* +	       * Remove association from the pthread_t chain +	       */ +	      *nextP = assoc->nextKey; + +	      pthread_mutex_unlock (&(assoc->lock)); + +	      _pthread_tkAssocDestroy (assoc); + +	      assoc = *nextP; +	    } +	} +    } + +}				/* callUserDestroyRoutines */ + +/* </JEB> */ + + +#if 0 /* Pre Bossom */ +  /* Thread ID management.     --------------------- @@ -141,3 +550,5 @@ _pthread_delete_thread(_pthread_t * thread)    return EINVAL;  } + +#endif /* Pre Bossom */ @@ -1,33 +1,191 @@  /* This is the POSIX thread API (POSIX 1003). - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public -License as published by the Free Software Foundation; either -version 2 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -/* FIXME: do not include function prototypes for functions which are -   not yet implemented.  This will allow us to keep a better handle on -   where we're at. */ - -#ifndef _PTHREADS_H -#define _PTHREADS_H - -/* Convert these to defined when implemented. */ -#define _POSIX_THREAD_ATTR_STACKSIZE -#ifdef _POSIX_THREAD_ATTR_STACKADDR -#undef _POSIX_THREAD_ATTR_STACKADDR + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Library General Public License for more details. + *  + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * ------------------------------------------------------------- + * + * + * Module: pthread.h + * + * Purpose: + *      Provides an implementation of PThreads based upon the + *      standard: + * + *              POSIX 1003.1c-1995      (POSIX.1c) + * + * Authors: + *      Contributors are listed in the file "MAINTAINERS". + * + * The following functions are implemented: + *      --------------------------- + *      PThreads + *      --------------------------- + *      pthread_attr_init + *      pthread_attr_destroy + *      pthread_attr_getdetachstate + *      pthread_attr_getstackaddr + *      pthread_attr_getstacksize + *      pthread_attr_setdetachstate      + *      pthread_attr_setstackaddr + *      pthread_attr_setstacksize + * + *      pthread_create + *      pthread_detach + *      pthread_equal + *      pthread_exit + *      pthread_join + *      pthread_self + *      sched_yield + * + *      pthread_cancel + *      pthread_cleanup_pop + *      pthread_cleanup_push + *      pthread_setcancelstate + *      pthread_setcanceltype + *      pthread_testcancel + * + *      --------------------------- + *      Thread Specific Data + *      --------------------------- + *      pthread_key_create + *      pthread_key_delete + *      pthread_setspecific + *      pthread_getspecific + * + *      --------------------------- + *      Mutexes + *      --------------------------- + *      pthread_mutexattr_init + *      pthread_mutexattr_destroy + *      pthread_mutexattr_getpshared + *      pthread_mutexattr_setpshared + * + *      pthread_mutex_init + *      pthread_mutex_destroy + *      pthread_mutex_lock + *      pthread_mutex_trylock + *      pthread_mutex_unlock + * + *      --------------------------- + *      Condition Variables + *      --------------------------- + *      pthread_condattr_init + *      pthread_condattr_destroy + *      pthread_condattr_getpshared + *      pthread_condattr_setpshared + * + *      pthread_cond_init + *      pthread_cond_destroy + *      pthread_cond_wait + *      pthread_cond_timedwait + *      pthread_cond_signal + *      pthread_cond_broadcast + * + *      --------------------------- + *      Protected Methods + *      --------------------------- + *      pthreadCancelableWait + * + * Limitations + * =========== + *      The following functions are not implemented: + * + *      --------------------------- + *      RealTime Scheduling: + *      --------------------------- + *      pthread_attr_getinheritsched + *      pthread_attr_getschedparam + *      pthread_attr_getschedpolicy + *      pthread_attr_getscope + *      pthread_attr_setinheritsched + *      pthread_attr_setschedparam + *      pthread_attr_setschedpolicy + *      pthread_attr_setscope + *      pthread_getschedparam + *      pthread_mutex_getprioceiling + *      pthread_mutex_setprioceiling + *      pthread_mutex_attr_getprioceiling + *      pthread_mutex_attr_getprotocol + *      pthread_mutex_attr_setprioceiling + *      pthread_mutex_attr_setprotocol + *      pthread_setschedparam + *      sched_get_priority_max + *      sched_get_priority_min + * + *      --------------------------- + *      Fork Handlers: + *      --------------------------- + *      pthread_atfork + * + *      --------------------------- + *      Stdio: + *      --------------------------- + *      flockfile + *      ftrylockfile + *      funlockfile + *      getc_unlocked + *      getchar_unlocked + *      putc_unlocked + *      putchar_unlocked + * + *      --------------------------- + *      Thread-Safe C Runtime Library: + *      --------------------------- + *      readdir_r + *      getgrgid_r + *      getgrnam_r + *      getpwuid_r + *      getpwnam_r + * + *      --------------------------- + *      Signals: + *      --------------------------- + *      pthread_kill + *      pthread_sigmask + *      sigtimedwait + *      sigwait + *      sigwaitinfo + * + * + * ------------------------------------------------------------- + */ +#if !defined( PTHREAD_H ) +#define PTHREAD_H + +#ifdef _WIN32 +/* + * Disable following warnings when including Windows headers + * + * warning C4115: named type definition in parentheses + * warning C4116: unnamed type definition in parentheses + * warning C4127: conditional expression is constant + * warning C4201: nonstandard extension used : nameless struct/union + * warning C4214: nonstandard extension used : bit field types other than int + * warning C4514: unreferenced inline function has been removed + */ +#pragma warning( disable : 4115 4116 4127 4201 4214 4514)  #endif +/* + * ----------------- + * autoconf switches + * ----------------- + */ +  #if HAVE_CONFIG_H  #include "config.h"  #endif /* HAVE_CONFIG_H */ @@ -58,299 +216,604 @@ struct timespec {  #define SIG_SETMASK 2  #endif /* SIG_SETMASK */ -#define PTHREAD_STACK_MIN   65535 - -/* Thread scheduling policies */ - -#define SCHED_OTHER 0 -#define SCHED_FIFO  1 -#define SCHED_RR    2 - -#define SCHED_MIN   SCHED_OTHER -#define SCHED_MAX   SCHED_RR - -/* Cancelation return value. -   This value must be neither NULL nor the value of any -   pointer to an object in memory. */ -#define PTHREAD_CANCELED            ((void *) 1) - -#define PTHREAD_MUTEX_INITIALIZER {0 /* ignore internals */ } -#define PTHREAD_ONCE_INIT { 0, PTHREAD_MUTEX_INITIALIZER } - -typedef struct _pthread * pthread_t; -typedef struct { -	int valid; -	CRITICAL_SECTION cs; -} pthread_mutex_t; - - -typedef DWORD pthread_key_t; - -/*                                      Related constants */ -typedef struct { -  long valid; +#include <process.h> +#include <errno.h> -#ifdef _POSIX_THREAD_ATTR_STACKSIZE -  size_t stacksize;                  /* PTHREAD_STACK_MIN */ +#ifdef _WIN32 +/* + * Re-enable all but 4127, 4514 + */ +#pragma warning( default : 4115 4116 4201 4214)  #endif -  int detachedstate;                 /* PTHREAD_CREATE_DETACHED -					PTHREAD_CREATE_JOINABLE */ +#if !defined( TRUE ) +#define TRUE	!FALSE +#define FALSE	0 +#endif /* !TRUE */ -#if HAVE_SIGSET_T -  sigset_t sigmask; -#endif /* HAVE_SIGSET_T */ -  int priority; +#include <semaphore.h> +#include <sched.h> -} pthread_attr_t; - -/* I don't know why this structure isn't in some kind of namespace. -   According to my O'Reilly book, this is what this struct is -   called. */ -struct sched_param { -  int sched_priority; -}; - -enum { SIGNAL, BROADCAST, NUM_EVENTS }; - -typedef struct { -  /* Signal and broadcast event HANDLEs. */ -  HANDLE events[NUM_EVENTS]; - -  /* Count of the number of waiters. */ -  unsigned waiters_count; -   -  /* Serialize access to waiters_count. */ -  pthread_mutex_t waiters_count_lock; -} pthread_cond_t; - -typedef struct { void * dummy; } pthread_condattr_t; -typedef struct { void * dummy; } pthread_mutexattr_t; - -typedef struct { -  unsigned short flag; -  pthread_mutex_t lock; -} pthread_once_t;  #ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -int pthread_atfork (void (*prepare)(void), -		    void (*parent)(void), -		    void (*child)(void)); - -int pthread_create(pthread_t *thread, -		   const pthread_attr_t *attr, -		   void * (*start_routine) (void *), -		   void * arg); +extern "C" +{ +#endif				/* __cplusplus */ + +/* + * ------------------------------------------------------------- + * + * POSIX 1003.1c-1995 Options + * =========================== + * + * _POSIX_SEMAPHORES + *                      Semaphores come from POSIX.1b (POSIX 1003.1b-1993) + *                      rather than from PThreads. This macro indicates + *                      that POSIX Semaphores are supported: + *                              sem_destroy + *                              sem_init + *                              sem_wait + *                              sem_trywait + *                              sem_post + * + * _POSIX_THREADS (set) + *                      If set, you can use threads + * + * _POSIX_THREAD_ATTR_STACKSIZE (set) + *                      If set, you can control the size of a thread's + *                      stack + *                              pthread_attr_getstacksize + *                              pthread_attr_setstacksize + * + * _POSIX_THREAD_ATTR_STACKADDR (not set) + *                      If set, you can allocate and control a thread's + *                      stack. If not supported, the following functions + *                      will return ENOSYS, indicating they are not + *                      supported: + *                              pthread_attr_getstackaddr + *                              pthread_attr_setstackaddr + * + * _POSIX_THREAD_PRIORITY_SCHEDULING (not set) + *                      If set, you can use realtime scheduling. + *                      Indicates the availability of: + *                              pthread_attr_getinheritsched + *                              pthread_attr_getschedparam + *                              pthread_attr_getschedpolicy + *                              pthread_attr_getscope + *                              pthread_attr_setinheritsched + *                              pthread_attr_setschedparam + *                              pthread_attr_setschedpolicy + *                              pthread_attr_setscope + *                              pthread_getschedparam + *                              pthread_setschedparam + *                              pthread_get_priority_max + *                              pthread_get_priority_min + * + * _POSIX_THREAD_PRIO_INHERIT (not set) + *                      If set, you can create priority inheritance + *                      mutexes. + *                              pthread_mutexattr_getprotocol + + *                              pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PRIO_PROTECT (not set) + *                      If set, you can create priority ceiling mutexes + *                      Indicates the availability of: + *                              pthread_mutex_getprioceiling + *                              pthread_mutex_setprioceiling + *                              pthread_mutexattr_getprioceiling + *                              pthread_mutexattr_getprotocol     + + *                              pthread_mutexattr_setprioceiling + *                              pthread_mutexattr_setprotocol     + + * + * _POSIX_THREAD_PROCESS_SHARED (not set) + *                      If set, you can create mutexes and condition + *                      variables that can be shared with another + *                      process.If set, indicates the availability + *                      of: + *                              pthread_mutexattr_getpshared + *                              pthread_mutexattr_setpshared + *                              pthread_condattr_getpshared + *                              pthread_condattr_setpshared + * + * _POSIX_THREAD_SAFE_FUNCTIONS (set) + *                      If set you can use the special *_r library + *                      functions that provide thread-safe behaviour + * + *      + These functions provide both 'inherit' and/or + *        'protect' protocol, based upon these macro + *        settings. + * + * POSIX 1003.1c-1995 Limits + * =========================== + * + * PTHREAD_DESTRUCTOR_ITERATIONS + *                      Maximum number of attempts to destroy + *                      a thread's thread-specific data on + *                      termination (must be at least 4) + * + * PTHREAD_KEYS_MAX + *                      Maximum number of thread-specific data keys + *                      available per process (must be at least 128) + * + * PTHREAD_STACK_MIN + *                      Minimum supported stack size for a thread + * + * PTHREAD_THREADS_MAX + *                      Maximum number of threads supported per + *                      process (must be at least 64). + * + * ------------------------------------------------------------- + */ + +/* + * POSIX Options + */ +#define _POSIX_THREADS +#define _POSIX_SEMAPHORES +#define _POSIX_THREAD_SAFE_FUNCTIONS -void pthread_exit(void *value); - -pthread_t pthread_self(void); +#define _POSIX_THREAD_ATTR_STACKSIZE -int pthread_equal(pthread_t t1, pthread_t t2); +#if defined( KLUDGE ) +/* + * The following are not supported + */ +#define _POSIX_THREAD_ATTR_STACKADDR +#define _POSIX_THREAD_PRIORITY_SCHEDULING +#define _POSIX_THREAD_PRIO_INHERIT +#define _POSIX_THREAD_PRIO_PROTECT +#define _POSIX_THREAD_PROCESS_SHARED + +#endif				/* KLUDGE */ + +/* + * POSIX Limits + * + *      PTHREAD_DESTRUCTOR_ITERATIONS + *              Standard states this must be at least + *              4. + * + *      PTHREAD_KEYS_MAX + *              WIN32 permits only 64 TLS keys per process. + *              This limitation could be worked around by + *              simply simulating keys. + * + *      PTHREADS_STACK_MIN + *              artibrarily chose 1K. By default, WIN32 + *              selects 1Meg stacks. + * + *      PTHREAD_THREADS_MAX + *              Not documented by WIN32. Wrote a test program + *              that kept creating threads until it failed + *              revealed this approximate number. + * + */ +#define PTHREAD_DESTRUCTOR_ITERATIONS	                   4 +#define PTHREAD_KEYS_MAX				  64 +#define PTHREAD_STACK_MIN				1024 +#define PTHREAD_THREADS_MAX				2019 + + +  typedef struct pthread_t_ *pthread_t; +  typedef struct pthread_attr_t_ pthread_attr_t; +  typedef struct pthread_once_t_ pthread_once_t; +  typedef struct pthread_key_t_ *pthread_key_t; +  typedef struct pthread_mutex_t_ pthread_mutex_t; +  typedef struct pthread_mutexattr_t_ pthread_mutexattr_t; +  typedef struct pthread_cond_t_ *pthread_cond_t; +  typedef struct pthread_condattr_t_ *pthread_condattr_t; + + +/* + * ==================== + * ==================== + * POSIX Threads + * ==================== + * ==================== + */ + +/* + * pthread_attr_{get,set}detachstate + */ +#define PTHREAD_CREATE_JOINABLE		0 +#define PTHREAD_CREATE_DETACHED		1 + +/* + * pthread_attr{get,set}inheritsched + */ +#define PTHREAD_INHERIT_SCHED		0 +#define PTHREAD_EXPLICIT_SCHED		1 + +/* + * pthread_setcancelstate paramters + */ +#define PTHREAD_CANCEL_ENABLE		0 +#define PTHREAD_CANCEL_DISABLE		1 + +/* + * pthread_setcanceltype parameters + */ +#define PTHREAD_CANCEL_ASYNCHRONOUS	0 +#define PTHREAD_CANCEL_DEFERRED		1 + +/* + * ==================== + * ==================== + * Mutex + * ==================== + * ==================== + */ + +/* FIXME: Replace the NULL with a valid critical section initializer + * and then also change the 0 (first element) to 1. + */ +#define PTHREAD_MUTEX_INITIALIZER { 0, NULL } + + +/* + * pthread_mutexattr_{get,set}pshared + * pthread_condattr_{get,set}pshared + */ +#define PTHREAD_PROCESS_PRIVATE		0 +#define PTHREAD_PROCESS_SHARED		1 + + +/* + * ==================== + * ==================== + * Once Key + * ==================== + * ==================== + */ +#define PTHREAD_ONCE_INIT	 { 0, PTHREAD_MUTEX_INITIALIZER } + + +/* + * ==================== + * ==================== + * Condition Variable + * ==================== + * ==================== + */ +#define PTHREAD_COND_INITIALIZER { {0, 0}, 0, PTHREAD_MUTEX_INITIALIZER } + + +/* + * ==================== + * ==================== + * Scheduling + * ==================== + * ==================== + */ -int pthread_join(pthread_t thread, void ** valueptr); +/* Thread scheduling policies */ -int pthread_detach(pthread_t thread); +#define SCHED_OTHER 0 +#define SCHED_FIFO  1 +#define SCHED_RR    2 -int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)); +#define SCHED_MIN   SCHED_OTHER +#define SCHED_MAX   SCHED_RR -/* Functions for manipulating thread attribute objects. */ +  struct sched_param { +    int sched_priority; +  }; + + + +/* There are three implementations of cancel cleanup. + * + *   C + *   C++ (as per Cygwin32 or Mingw32) + *   WIN32 SEH or C++ + */ + +#ifndef __cplusplus + +/* + * C implementation of PThreads cancel cleanup + */ +  typedef struct pthread_cleanup_t pthread_cleanup_t; + +  struct pthread_cleanup_t +    { +      void (*routine) (void *); +      void *arg; +      pthread_cleanup_t *prev; +    }; + +#define pthread_cleanup_push( _rout, _arg ) \ +	{ \ +	    pthread_cleanup_t	cleanup; \ +            \ +	    pthread_push_cleanup( &cleanup, (_rout), (_arg) ); \ + +#define pthread_cleanup_pop( _execute ) \ +	    (void) pthread_pop_cleanup( _execute ); \ +	} + +#else /* !__cplusplus */ + +#ifdef _WIN32 +	/* +	 * WIN32 SEH version of cancel cleanup. +	 */ + +#define pthread_cleanup_push( _rout, _arg ) \ +	{ \ +	    pthread_cleanup_t	_cleanup; \ +	    \ +            _cleanup.routine	= (_rout); \ +	    _cleanup.arg	= (_arg); \ +	    __try \ +	      { \ + +#define pthread_cleanup_pop( _execute ) \ +	      } \ +	    __finally \ +		{ \ +		    if( _execute || AbnormalTermination()) \ +		      { \ +			  (*(_cleanup.routine))( _cleanup.arg ); \ +		      } \ +		} \ +	} + +#else /* _WIN32 */ + +	/* +	 * C++ (ie. Cygwin32 or Mingw32) version of cancel cleanup. +	 * +	 * Emulate try-finally behaviour. +	 */ + +#define pthread_cleanup_push( _rout, _arg ) \ +	{ \ +	    pthread_cleanup_t	_cleanup; \ +	    \ +            _cleanup.routine	= (_rout); \ +	    _cleanup.arg	= (_arg); \ +	    try \ +	      { \ + +#define pthread_cleanup_pop( _execute ) \ +	      } \ +	    catch(...) \ +	      { \ +		  (*(_cleanup.routine))( _cleanup.arg ); \ +		  \ +		  throw; \ +	      } \ +              \ +	      if (_execute) \ +		{ \ +		    (*(_cleanup.routine))( _cleanup.arg ); \ +		} \ +      	} -int pthread_attr_init(pthread_attr_t *attr); +#endif /* _WIN32 */ -int pthread_attr_destroy(pthread_attr_t *attr); +#endif /* !__cplusplus */ -int pthread_attr_setstacksize(pthread_attr_t *attr, -			      size_t stacksize); +/* + * =============== + * =============== + * Methods + * =============== + * =============== + */ + +/* + * PThread Attribute Functions + */ +int pthread_attr_init (pthread_attr_t * attr); -int pthread_attr_getstacksize(const pthread_attr_t *attr, -			      size_t *stacksize); +int pthread_attr_destroy (pthread_attr_t * attr); -int pthread_attr_setstackaddr(pthread_attr_t *attr, -			      void *stackaddr); +int pthread_attr_getdetachstate (const pthread_attr_t * attr, +				 int *detachstate); -int pthread_attr_getstackaddr(const pthread_attr_t *attr, -			      void **stackaddr); +int pthread_attr_getstackaddr (const pthread_attr_t * attr, +			       void **stackaddr); -int pthread_attr_getschedparam(const pthread_attr_t *attr, -			       struct sched_param *param); +int pthread_attr_getstacksize (const pthread_attr_t * attr, +			       size_t * stacksize); -int pthread_attr_setschedparam(pthread_attr_t *attr, -			       const struct sched_param *param); +int pthread_attr_setdetachstate (pthread_attr_t * attr, +				 int detachstate); -int pthread_attr_getdetachstate(const pthread_attr_t *attr, -				int *detachstate); +int pthread_attr_setstackaddr (pthread_attr_t * attr, +			       void *stackaddr); -int pthread_attr_setdetachstate(pthread_attr_t *attr, -				int detachstate); -   -int pthread_setschedparam(pthread_t thread, -			  int policy, -			  const struct sched_param *param); +int pthread_attr_setstacksize (pthread_attr_t * attr, +			       size_t stacksize); -int pthread_getschedparam(pthread_t thread, -			  int *policy, -			  struct sched_param *param); +/* + * PThread Functions + */ +int pthread_create (pthread_t * tid, +		    const pthread_attr_t * attr, +		    void *(*start) (void *), +		    void *arg); -int sched_get_priority_min(int policy); +int pthread_detach (pthread_t tid); -int sched_get_priority_max(int policy); +int pthread_equal (pthread_t t1, +		   pthread_t t2); -int pthread_setcancelstate(int state, -			   int *oldstate); +int pthread_exit (void *value_ptr); -int pthread_setcanceltype(int type, -			  int *oldtype); +int pthread_join (pthread_t thread, +		  void **value_ptr); -/* Functions for manipulating cond. var. attribute objects. */ +pthread_t pthread_self (void); -int pthread_condattr_init(pthread_condattr_t *attr); +int pthread_cancel (pthread_t thread); -int pthread_condattr_setpshared(pthread_condattr_t *attr, -			       int pshared); +pthread_cleanup_t *pthread_pop_cleanup (int execute); -int pthread_condattr_getpshared(pthread_condattr_t *attr, -				int *pshared); +void pthread_push_cleanup (pthread_cleanup_t * cleanup, +			   void (*routine) (void *), +			   void *arg); -int pthread_condattr_destroy(pthread_condattr_t *attr); +int pthread_setcancelstate (int state, +			    int *oldstate); -/* Functions for manipulating mutex attribute objects. */ +int pthread_setcanceltype (int type, +			   int *oldtype); -int pthread_mutexattr_init(pthread_mutexattr_t *attr); +void pthread_testcancel (void); -int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); +int pthread_once (pthread_once_t * once_control, +		  void (*init_routine) (void)); -/* Primitives for condition variables. */ +/* + * Thread Specific Data Functions + */ +int pthread_key_create (pthread_key_t * key, +			void (*destructor) (void *)); -int pthread_cond_init(pthread_cond_t *cv, -		      const pthread_condattr_t *attr); +int pthread_key_delete (pthread_key_t key); -int pthread_cond_broadcast(pthread_cond_t *cv); +int pthread_setspecific (pthread_key_t key, +			 const void *value); -int pthread_cond_signal(pthread_cond_t *cv); +void *pthread_getspecific (pthread_key_t key); -int pthread_cond_timedwait(pthread_cond_t *cv, -			   pthread_mutex_t *mutex, -			   const struct timespec *abstime); -int pthread_cond_wait(pthread_cond_t *cv, -		      pthread_mutex_t *mutex); +/* + * Mutex Attribute Functions + */ +int pthread_mutexattr_init (pthread_mutexattr_t * attr); -int pthread_cond_destroy(pthread_cond_t *cv); +int pthread_mutexattr_destroy (pthread_mutexattr_t * attr); -/* Primitives for mutexes. */ +int pthread_mutexattr_getpshared (const pthread_mutexattr_t +				  * attr, +				  int *pshared); -int pthread_mutex_init(pthread_mutex_t *mutex, -		       const pthread_mutexattr_t *attr); +int pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, +				  int pshared); -int pthread_mutex_destroy(pthread_mutex_t *mutex); +/* + * Mutex Functions + */ +int pthread_mutex_init (pthread_mutex_t * mutex, +			const pthread_mutexattr_t * attr); -int pthread_mutex_lock(pthread_mutex_t *mutex); +int pthread_mutex_destroy (pthread_mutex_t * mutex); -int pthread_mutex_trylock(pthread_mutex_t *mutex); +int pthread_mutex_lock (pthread_mutex_t * mutex); -int pthread_mutex_unlock(pthread_mutex_t *mutex); +int pthread_mutex_trylock (pthread_mutex_t * mutex); -/* Primitives for thread-specific data (TSD). */ +int pthread_mutex_unlock (pthread_mutex_t * mutex); -int pthread_key_create(pthread_key_t *key, -		       void (*destructor)(void *)); +/* + * Condition Variable Attribute Functions + */ +int pthread_condattr_init (pthread_condattr_t * attr); -int pthread_setspecific(pthread_key_t key, void *value); +int pthread_condattr_destroy (pthread_condattr_t * attr); -void *pthread_getspecific(pthread_key_t key); +int pthread_condattr_getpshared (const pthread_condattr_t * attr, +				 int *pshared); -int pthread_key_delete(pthread_key_t key); +int pthread_condattr_setpshared (pthread_condattr_t * attr, +				 int pshared); -/* Signal handling. */ +/* + * Condition Variable Functions + */ +int pthread_cond_init (pthread_cond_t * cond, +		       const pthread_condattr_t * attr); -#if HAVE_SIGSET_T -int pthread_sigmask(int how, -		    const sigset_t *set, -		    sigset_t *oset); -#endif /* HAVE_SIGSET_T */ +int pthread_cond_destroy (pthread_cond_t * cond); -/* Thread cancelation functions. */ +int pthread_cond_wait (pthread_cond_t * cond, +		       pthread_mutex_t * mutex); -void pthread_testcancel(void); +int pthread_cond_timedwait (pthread_cond_t * cond, +			    pthread_mutex_t * mutex, +			    const struct timespec *abstime); -int pthread_cancel(pthread_t thread); +int pthread_cond_signal (pthread_cond_t * cond); -#ifdef __cplusplus -} -#endif /* __cplusplus */ +int pthread_cond_broadcast (pthread_cond_t * cond); -/* Constants declared in global.c */ -extern const int _POSIX_THREAD_THREADS_MAX; -extern const int _POSIX_THREAD_DESTRUCTOR_ITERATIONS; -extern const int _POSIX_THREAD_KEYS_MAX; +/* + * Scheduling + */ -extern const int _pthread_create_joinable; -extern const int _pthread_create_detached; +int pthread_setschedparam (pthread_t thread, +			   int policy, +			   const struct sched_param *param); -extern const int _pthread_cancel_enable; -extern const int _pthread_cancel_disable; +int pthread_getschedparam (pthread_t thread, +			   int *policy, +			   struct sched_param *param); -extern const int _pthread_cancel_asynchronous; -extern const int _pthread_cancel_deferred; +int sched_get_priority_min (int policy); -#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS -#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX -#define PTHREAD_THREADS_MAX _POSIX_THREAD_THREADS_MAX +int sched_get_priority_max (int policy); -#define PTHREAD_CREATE_JOINABLE     _pthread_create_joinable -#define PTHREAD_CREATE_DETACHED     _pthread_create_detached +int pthread_attr_getschedparam (const pthread_attr_t *attr, +				struct sched_param *param); -/* Cancelability attributes */ -#define PTHREAD_CANCEL_ENABLE       _pthread_cancel_enable -#define PTHREAD_CANCEL_DISABLE      _pthread_cancel_disable +int pthread_attr_setschedparam (pthread_attr_t *attr, +				const struct sched_param *param); -#define PTHREAD_CANCEL_ASYNCHRONOUS _pthread_cancel_asynchronous -#define PTHREAD_CANCEL_DEFERRED     _pthread_cancel_deferred +/* + * Protected Methods + * + * This function blocks until the given WIN32 handle + * is signaled or pthread_cancel had been called. + * This function allows the caller to hook into the + * PThreads cancel mechanism. It is implemented using + * + *              WaitForMultipleObjects + * + * on 'waitHandle' and a manually reset WIN32 Event + * used to implement pthread_cancel. + */ +int pthreadCancelableWait (HANDLE waitHandle); -/* The following #defines implement POSIX cleanup handlers. -   The standard requires that these functions be used as statements and -   be used pairwise in the same scope. The standard suggests that, in C, they -   may be implemented as macros starting and ending the same block. +/* + * Thread-Safe C Runtime Library Mappings + * WIN32 C runtime library had been made thread-safe + * without affecting the user interface. Provide + * mappings from the UNIX thread-safe versions to + * the standard C runtime library calls. + * Only provide function mappings for functions that + * actually exist on WIN32. + */ +#define strtok_r( _s, _sep, _lasts ) \ +	( *(_lasts) = strtok( (_s), (_sep) ) ) -   POSIX requires that applications observe scoping requirements, but -   doesn't say if the implemention must enforce them. The macros below -   partially enforce scope but can lead to compile or runtime errors. */ +#define asctime_r( _tm, _buf ) \ +	( strcpy( (_buf), asctime( (_tm) ) ), \ +	  (_buf) ) -enum { -  _PTHREAD_HANDLER_POP_LIFO, -  _PTHREAD_HANDLER_POP_FIFO -}; +#define ctime_r( _clock, _buf ) \ +	( strcpy( (_buf), ctime( (_tm) ) ), \ +	  (_buf) ) -enum { -  _PTHREAD_CLEANUP_STACK, -  _PTHREAD_DESTRUCTOR_STACK, -  _PTHREAD_FORKPREPARE_STACK, -  _PTHREAD_FORKPARENT_STACK, -  _PTHREAD_FORKCHILD_STACK -}; +#define gmtime_r( _clock, _result ) \ +	( *(_result) = *gmtime( (_clock) ), \ +	  (_result) ) -#ifdef pthread_cleanup_push -#undef pthread_cleanup_push -#endif +#define localtime_r( _clock, _result ) \ +	( *(_result) = *localtime( (_clock) ), \ +	  (_result) ) -#define pthread_cleanup_push(routine, arg) \ -{ \ -  (void ) _pthread_handler_push(_PTHREAD_CLEANUP_STACK, \ -				_PTHREAD_HANDLER_POP_LIFO, routine, arg); +#define rand_r( _seed ) \ +	rand() -#ifdef pthread_cleanup_pop -#undef pthread_cleanup_pop -#endif -#define pthread_cleanup_pop(execute) \ -  _pthread_handler_pop(_PTHREAD_CLEANUP_STACK, execute);\ -} +#ifdef __cplusplus +}				/* End of extern "C" */ +#endif				/* __cplusplus */ -#endif /* _PTHREADS_H */ @@ -6,6 +6,125 @@   * synchronisation.   */ +/* + * Code contributed by John E. Bossom <JEB>. + */ + +int +pthread_detach (pthread_t tid) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function detaches the given thread. +      * +      * PARAMETERS +      *      thread +      *              an instance of a pthread_t +      * +      * +      * DESCRIPTION +      *      This function detaches the given thread. You may +      *      detach the main thread or to detach a joinable thread +      *      (You should have used pthread_attr_t to create the +      *      thread as detached!) +      *      NOTE:   detached threads cannot be joined nor canceled; +      *                      storage is freed immediately on termination. +      * +      * RESULTS +      *              0               successfully detached the thread, +      *              EINVAL          thread is not a joinable thread, +      *              ENOSPC          a required resource has been exhausted, +      *              ESRCH           no thread could be found for 'thread', +      * +      * ------------------------------------------------------ +      */ +{ +  int result; + +  if (tid == NULL || +      tid->detachState == PTHREAD_CREATE_DETACHED) +    { + +      result = EINVAL; + +    } +  else +    { +      result = 0; +      tid->detachState = PTHREAD_CREATE_DETACHED; +    } + +  return (result); + +}				/* pthread_detach */ + +int +pthread_join (pthread_t thread, void **value_ptr) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function waits for 'thread' to terminate and +      *      returns the thread's exit value if 'value_ptr' is not +      *      NULL. This also detaches the thread on successful +      *      completion. +      * +      * PARAMETERS +      *      sem +      *              pointer to an instance of sem_t +      * +      * +      * DESCRIPTION +      *      This function waits for 'thread' to terminate and +      *      returns the thread's exit value if 'value_ptr' is not +      *      NULL. This also detaches the thread on successful +      *      completion. +      *      NOTE:   detached threads cannot be joined or canceled +      * +      * RESULTS +      *              0               'thread' has completed +      *              EINVAL          thread is not a joinable thread, +      *              ESRCH           no thread could be found with ID 'thread', +      *              EDEADLK         attempt to join thread with self +      * +      * ------------------------------------------------------ +      */ +{ +  int result = 0; +  pthread_t self; + +  self = pthread_self (); + +  if (pthread_equal (self, thread) == 0) +    { +      result = EDEADLK; + +    } +  else +    { +      DWORD stat; + +      stat = WaitForSingleObject (thread->threadH, INFINITE); + +      if (stat != WAIT_OBJECT_0 && +	  !GetExitCodeThread (thread->threadH, (LPDWORD) value_ptr)) +	{ +	  result = ESRCH; +	} +      else +	{ +	  threadDestroy (thread); +	} +    } + +  return (result); + +}				/* pthread_join */ + +/* </JEB> */ + + +#if 0 /* Pre Bossom */ +  #include <errno.h>  /* POSIX STANDARD: A thread may pass a value pointer to some data via @@ -186,3 +305,5 @@ pthread_detach(pthread_t thread)    return ret;  } + +#endif /* Pre Bossom */ @@ -48,6 +48,312 @@   * One more thing to note: destructors must never be called on deleted keys.   */ +#include "pthread.h" +#include "implement.h" + +/* + * Code contributed by John E. Bossom <JEB>. + */ + +int +pthread_key_create (pthread_key_t * key, void (*destructor) (void *)) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function creates a thread-specific data key visible +      *      to all threads. All existing and new threads have a value +      *      NULL for key until set using pthread_setspecific. When any +      *      thread with a non-NULL value for key terminates, 'destructor' +      *      is called with key's current value for that thread. +      * +      * PARAMETERS +      *      key +      *              pointer to an instance of pthread_key_t +      * +      * +      * DESCRIPTION +      *      This function creates a thread-specific data key visible +      *      to all threads. All existing and new threads have a value +      *      NULL for key until set using pthread_setspecific. When any +      *      thread with a non-NULL value for key terminates, 'destructor' +      *      is called with key's current value for that thread. +      * +      * RESULTS +      *              0               successfully created semaphore, +      *              EAGAIN          insufficient resources or PTHREAD_KEYS_MAX +      *                              exceeded, +      *              ENOMEM          insufficient memory to create the key, +      * +      * ------------------------------------------------------ +      */ +{ +  int result = 0; +   +  if ((*key = (pthread_key_t) calloc (1, sizeof (**key))) == NULL) +    { +      result = ENOMEM; +    } +  else if (((*key)->key = TlsAlloc ()) == TLS_OUT_OF_INDEXES) +    { +      /* +       * Create system key +       */ +      result = EAGAIN; + +      free (*key); +      *key = NULL; +    } +  else if (destructor != NULL) +    { +      /* +       * Have to manage associations between thread and key; +       * Therefore, need a lock that allows multiple threads +       * to gain exclusive access to the key->threads list +       */ +      result = pthread_mutex_init (&((*key)->threadsLock), NULL); + +      if (result != 0) +        { +          TlsFree ((*key)->key); + +          free (*key); +          *key = NULL; +        } +      (*key)->destructor = destructor; +    } + +  return (result); +} + +int +pthread_key_delete (pthread_key_t key) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function deletes a thread-specific data key. This +      *      does not change the value of the thread spcific data key +      *      for any thread and does not run the key's destructor +      *      in any thread so it should be used with caution. +      * +      * PARAMETERS +      *      key +      *              pointer to an instance of pthread_key_t +      * +      * +      * DESCRIPTION +      *      This function deletes a thread-specific data key. This +      *      does not change the value of the thread spcific data key +      *      for any thread and does not run the key's destructor +      *      in any thread so it should be used with caution. +      * +      * RESULTS +      *              0               successfully deleted the key, +      *              EINVAL          key is invalid, +      * +      * ------------------------------------------------------ +      */ +{ +  int result = 0; + +  if (key != NULL) +    { +      if (key->threads != NULL && +          pthread_mutex_lock (&(key->threadsLock)) == 0) +        { +          /* +           * Run through all Thread<-->Key associations +           * for this key. +           * If the pthread_t still exits (ie the assoc->thread +           * is not NULL) then leave the assoc for the thread to +           * destroy. +           * Notes: +           *      If assoc->thread is NULL, then the associated thread +           *      is no longer referencing this assoc. +           *      The association is only referenced +           *      by this key and must be released; otherwise +           *      the assoc will be destroyed when the thread is destroyed. +           */ +          ThreadKeyAssoc *assoc; + +          assoc = (ThreadKeyAssoc *) key->threads; + +          while (assoc != NULL) +            { +              if (pthread_mutex_lock (&(assoc->lock)) == 0) +                { +                  ThreadKeyAssoc *next; + +                  assoc->key = NULL; +                  next = assoc->nextThread; +                  assoc->nextThread = NULL; + +                  pthread_mutex_unlock (&(assoc->lock)); + +                  tkAssocDestroy (assoc); + +                  assoc = next; +                } +            } +          pthread_mutex_unlock (&(key->threadsLock)); +        } + +      TlsFree (key->key); +      if (key->destructor != NULL) +        { +          pthread_mutex_destroy (&(key->threadsLock)); +        } + +#if defined( _DEBUG ) +      memset ((char *) key, 0, sizeof (*key)); +#endif +      free (key); +    } + +  return (result); +} + + +int +pthread_setspecific (pthread_key_t key, const void *value) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function initializes an unnamed semaphore. the +      *      initial value of the semaphore is 'value' +      * +      * PARAMETERS +      *      sem +      *              pointer to an instance of sem_t +      * +      * +      * DESCRIPTION +      *      This function  initializes an unnamed semaphore. The +      *      initial value of the semaphore is set to 'value'. +      * +      * RESULTS +      *              0               successfully created semaphore, +      *              EINVAL          'sem' is not a valid semaphore, +      *              ENOSPC          a required resource has been exhausted, +      *              ENOSYS          semaphores are not supported, +      *              EPERM           the process lacks appropriate privilege +      * +      * ------------------------------------------------------ +      */ +{ +  pthread_t self; +  int result = 0; + +  if (key != _pthread_selfThreadKey) +    { +      /* +       * Using pthread_self will implicitly create +       * an instance of pthread_t for the current +       * thread if one wasn't explicitly created +       */ +      self = pthread_self (); +    } +  else +    { +      /* +       * Resolve catch-22 of registering thread with threadSelf +       * key +       */ +      self = pthread_getspecific (_pthread_selfThreadKey); +      if (self == NULL) +        { +          self = (pthread_t) value; +        } +    } + +  result = 0; + +  if (key != NULL) +    { +      ThreadKeyAssoc *assoc; + +      if (self != NULL && +          key->destructor != NULL && +          value != NULL) +        { +          /* +           * Only require associations if we have to +           * call user destroy routine. +           * Don't need to locate an existing association +           * when setting data to NULL for WIN32 since the +           * data is stored with the operating system; not +           * on the association; setting assoc to NULL short +           * circuits the search. +           */ +          assoc = (ThreadKeyAssoc *) self->keys; +          /* +           * Locate existing association +           */ +          while (assoc != NULL) +            { +              if (assoc->key == key) +                { +                  /* +                   * Association already exists +                   */ +                  break; +                } +              assoc = assoc->nextKey; +            } + +          /* +           * create an association if not found +           */ +          result = (assoc == NULL) +            ? tkAssocCreate (&assoc, self, key) +            : 0; +        } +      else +        { +          result = 0; +        } + +      if (result == 0) +        { +          TlsSetValue (key->key, (LPVOID) value); +        } +    } +  return (result); +}                               /* pthread_setspecific */ + + +void * +pthread_getspecific (pthread_key_t key) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function returns the current value of key in the +      *      calling thread. If no value has been set for 'key' in  +      *      the thread, NULL is returned. +      * +      * PARAMETERS +      *      key +      *              an instance of pthread_key_t +      * +      * +      * DESCRIPTION +      *      This function returns the current value of key in the +      *      calling thread. If no value has been set for 'key' in  +      *      the thread, NULL is returned. +      * +      * RESULTS +      *              key value +      * +      * ------------------------------------------------------ +      */ +{ +  return (TlsGetValue (key->key)); +} + +/* </JEB> */ + + +#if 0 /* Pre Bossom */ +  #include <errno.h>  #include "pthread.h" @@ -204,3 +510,4 @@ pthread_key_delete(pthread_key_t key)    return ret;  } +#endif /* Pre Bossom */ | 
