diff options
| -rw-r--r-- | ChangeLog | 69 | ||||
| -rw-r--r-- | attr.c | 354 | ||||
| -rw-r--r-- | buildlib.bat | 3 | ||||
| -rw-r--r-- | cleanup.c | 135 | ||||
| -rw-r--r-- | create.c | 7 | ||||
| -rw-r--r-- | dll.c | 4 | ||||
| -rw-r--r-- | fork.c | 6 | ||||
| -rw-r--r-- | implement.h | 101 | ||||
| -rw-r--r-- | misc.c | 1 | ||||
| -rw-r--r-- | private.c | 2 | ||||
| -rw-r--r-- | pthread.def | 4 | ||||
| -rw-r--r-- | pthread.h | 160 | ||||
| -rw-r--r-- | sched.c | 20 | ||||
| -rw-r--r-- | semaphore.c | 257 | ||||
| -rw-r--r-- | semaphore.h | 65 | ||||
| -rw-r--r-- | sync.c | 5 | ||||
| -rw-r--r-- | tsd.c | 4 | 
17 files changed, 1039 insertions, 158 deletions
| @@ -1,3 +1,72 @@ +Tue Dec 29 13:11:16 1998  Ross Johnson  <rpj@ixobrychus.canberra.edu.au> + +	* implement.h: Move the following struct definitions to pthread.h: +	pthread_t_, pthread_attr_t_, pthread_mutex_t_, pthread_mutex_t_, +	pthread_mutexattr_t_, pthread_key_t_, pthread_cond_t_, +	pthread_condattr_t_, pthread_once_t_. + +	* pthread.h: Add "_" prefix to pthread_push_cleanup and  +	pthread_pop_cleanup internal routines, and associated struct and +	typedefs. + +	* buildlib.bat: Add compile command for semaphore.c + +	* pthread.def: Comment out pthread_atfork routine name.  +	Now unimplemented. + +	* tsd.c (pthread_setspecific): Rename tkAssocCreate to +	_pthread_tkAssocCreate. +	(pthread_key_delete): Rename tkAssocDestroy to +	_pthread_tkAssocDestroy. + +	* sync.c (pthread_join): Rename threadDestroy to _pthread_threadDestroy + +	* sched.c (is_attr): attr is now **attr (was *attr), so add extra +	NULL pointer test. +	(pthread_attr_setschedparam): Increase redirection for attr which is +	now a **. +	(pthread_attr_getschedparam): Ditto. +	(pthread_setschedparam): Change thread validation and rename "thread" + 	Win32 thread Handle element name to match John Bossom's version. +	(pthread_getschedparam): Ditto. + +	* private.c (_pthread_threadDestroy): Rename call to +	callUserDestroyRoutines() as _pthread_callUserDestroyRoutines() + +	* misc.c: Add #include "implement.h". + +	* dll.c: Remove defined(KLUDGE) wrapped code. + +	* fork.c: Remove redefinition of ENOMEM. + +	* create.c (pthread_create): Rename threadStart and threadDestroy calls +	to _pthread_threadStart and _pthread_threadDestroy. + +	* implement.h: Rename "detachedstate" to "detachstate". + +	* attr.c: Rename "detachedstate" to "detachstate". + +Mon Dec 28 09:54:39 1998  Ross Johnson  <rpj@ixobrychus.canberra.edu.au> + +	* pthread.h (pthread_attr_t_): Change to *pthread_attr_t. + +	* attr.c (pthread_attr_setstacksize): Merge with John Bossom's version. +	(pthread_attr_getstacksize): Merge with John Bossom's version. +	(pthread_attr_setstackaddr): Merge with John Bossom's version. +	(pthread_attr_getstackaddr): Merge with John Bossom's version. +	(pthread_attr_init): Merge with John Bossom's version. +	(pthread_attr_destroy): Merge with John Bossom's version. +	(pthread_attr_getdetachstate): Merge with John Bossom's version. +	(pthread_attr_setdetachstate): Merge with John Bossom's version. +	(is_attr): attr is now **attr (was *attr), so add extra NULL pointer +	test. + +	* implement.h (pthread_attr_t_): Add and rename elements in JEB's +	version to correspond to original, so that it can be used with +	original attr routines. + +	* pthread.h: Add #endif at end which was truncated in merging. +  Sun Dec 20 14:51:58 1998  Ross Johnson  <rpj@ixobrychus.canberra.edu.au>  	* misc.c (pthreadCancelableWait): New function by John Bossom. Non-standard @@ -16,15 +16,57 @@ is_attr(const pthread_attr_t *attr)  {    /* Return 0 if the attr object is valid, non-zero otherwise. */ -  return (attr == NULL || attr->valid != _PTHREAD_ATTR_VALID); +  return (attr == NULL ||  +	  *attr == NULL ||  +	  (*attr)->valid != _PTHREAD_ATTR_VALID);  } -#ifdef _POSIX_THREAD_ATTR_STACKSIZE  int  pthread_attr_setstacksize(pthread_attr_t *attr,  			  size_t stacksize) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function specifies the size of the stack on +      *      which threads created with 'attr' will run. +      * +      * PARAMETERS +      *      attr +      *              pointer to an instance of pthread_attr_t +      * +      *      stacksize +      *              stack size, in bytes. +      * +      * +      * DESCRIPTION +      *      This function specifies the size of the stack on +      *      which threads created with 'attr' will run. +      * +      *      NOTES: +      *              1)      Function supported only if this macro is +      *                      defined: +      * +      *                              _POSIX_THREAD_ATTR_STACKSIZE +      * +      *              2)      Find the default first (using +      *                      pthread_attr_getstacksize), then increase +      *                      by multiplying. +      * +      *              3)      Only use if thread needs more than the +      *                      default. +      * +      * RESULTS +      *              0               successfully set stack size, +      *              EINVAL          'attr' is invalid or stacksize too +      *                              small or too big. +      *              ENOSYS          function not supported +      * +      * ------------------------------------------------------ +      */  { +#ifdef _POSIX_THREAD_ATTR_STACKSIZE +    /* Verify that the stack size is within range. */    if (stacksize < PTHREAD_STACK_MIN)      { @@ -37,89 +79,295 @@ pthread_attr_setstacksize(pthread_attr_t *attr,      }    /* Everything is okay. */ -  attr->stacksize = stacksize; +  (*attr)->stacksize = stacksize;    return 0; + +#else + +  return ENOSYS; + +#endif /* _POSIX_THREAD_ATTR_STACKSIZE */ +  }  int  pthread_attr_getstacksize(const pthread_attr_t *attr,  			  size_t *stacksize) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function determines the size of the stack on +      *      which threads created with 'attr' will run. +      * +      * PARAMETERS +      *      attr +      *              pointer to an instance of pthread_attr_t +      * +      *      stacksize +      *              pointer to size_t into which is returned the +      *              stack size, in bytes. +      * +      * +      * DESCRIPTION +      *      This function determines the size of the stack on +      *      which threads created with 'attr' will run. +      * +      *      NOTES: +      *              1)      Function supported only if this macro is +      *                      defined: +      * +      *                              _POSIX_THREAD_ATTR_STACKSIZE +      * +      *              2)      Use on newly created attributes object to +      *                      find the default stack size. +      * +      * RESULTS +      *              0               successfully retrieved stack size, +      *              EINVAL          'attr' is invalid +      *              ENOSYS          function not supported +      * +      * ------------------------------------------------------ +      */  { +#ifdef _POSIX_THREAD_ATTR_STACKSIZE +    if (is_attr(attr) != 0)      {        return EINVAL;      }    /* Everything is okay. */ -  *stacksize = attr->stacksize; +  *stacksize = (*attr)->stacksize;    return 0; -} + +#else + +  return ENOSYS;  #endif /* _POSIX_THREAD_ATTR_STACKSIZE */ -#ifdef _POSIX_THREAD_ATTR_STACKADDR +} +  int  pthread_attr_setstackaddr(pthread_attr_t *attr,  			  void *stackaddr) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      Threads created with 'attr' will run on the stack +      *      starting at 'stackaddr'. +      *      Stack must be at least PTHREAD_STACK_MIN bytes. +      * +      * PARAMETERS +      *      attr +      *              pointer to an instance of pthread_attr_t +      * +      *      stacksize +      *              stack size, in bytes. +      * +      * +      * DESCRIPTION +      *      Threads created with 'attr' will run on the stack +      *      starting at 'stackaddr'. +      *      Stack must be at least PTHREAD_STACK_MIN bytes. +      * +      *      NOTES: +      *              1)      Function supported only if this macro is +      *                      defined: +      * +      *                              _POSIX_THREAD_ATTR_STACKADDR +      * +      *              2)      Create only one thread for each stack +      *                      address.. +      * +      *              3)      Ensure that stackaddr is aligned. +      * +      * RESULTS +      *              0               successfully set stack address, +      *              EINVAL          'attr' is invalid +      *              ENOSYS          function not supported +      * +      * ------------------------------------------------------ +      */  { +#if defined( _POSIX_THREAD_ATTR_STACKADDR ) +    if (is_attr(attr) != 0)      {        return EINVAL;      } + +  (*attr)->stackaddr = stackaddr; +  return 0; + +#else +    return ENOSYS; + +#endif /* _POSIX_THREAD_ATTR_STACKADDR */  }  int  pthread_attr_getstackaddr(const pthread_attr_t *attr,  			  void **stackaddr) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function determines the address of the stack +      *      on which threads created with 'attr' will run. +      * +      * PARAMETERS +      *      attr +      *              pointer to an instance of pthread_attr_t +      * +      *      stackaddr +      *              pointer into which is returned the stack address. +      * +      * +      * DESCRIPTION +      *      This function determines the address of the stack +      *      on which threads created with 'attr' will run. +      * +      *      NOTES: +      *              1)      Function supported only if this macro is +      *                      defined: +      * +      *                              _POSIX_THREAD_ATTR_STACKADDR +      * +      *              2)      Create only one thread for each stack +      *                      address.. +      * +      * RESULTS +      *              0               successfully retreived stack address, +      *              EINVAL          'attr' is invalid +      *              ENOSYS          function not supported +      * +      * ------------------------------------------------------ +      */  { +#if defined( _POSIX_THREAD_ATTR_STACKADDR ) +      if (is_attr(attr) != 0)      {        return EINVAL;      } + +  *stackaddr = (*attr)->stackaddr; +  return 0; + +#else +    return ENOSYS; -}  #endif /* _POSIX_THREAD_ATTR_STACKADDR */ +}  int  pthread_attr_init(pthread_attr_t *attr) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      Initializes a thread attributes object with default +      *      attributes. +      * +      * PARAMETERS +      *      attr +      *              pointer to an instance of pthread_attr_t +      * +      * +      * DESCRIPTION +      *      Initializes a thread attributes object with default +      *      attributes. +      * +      *      NOTES: +      *              1)      Used to define thread attributes +      * +      * RESULTS +      *              0               successfully initialized attr, +      *              ENOMEM          insufficient memory for attr. +      * +      * ------------------------------------------------------ +      */  { +  pthread_attr_t attr_result; +  int result = 0; +    if (attr == NULL)      {        /* This is disallowed. */        return EINVAL;      } +  attr_result = malloc (sizeof (*attr_result)); + +  if (attr_result == NULL) +    { +      return ENOMEM; +    } +  #ifdef _POSIX_THREAD_ATTR_STACKSIZE -  attr->stacksize = PTHREAD_STACK_MIN; +  attr_result->stacksize = PTHREAD_STACK_MIN; +#endif + +#ifdef _POSIX_THREAD_ATTR_STACKADDR +  /* FIXME: Set this to something sensible when we support it. */ +  attr_result->stackaddr = NULL;  #endif -  attr->detachedstate = PTHREAD_CREATE_JOINABLE; +  attr_result->detachstate = PTHREAD_CREATE_JOINABLE; +  #if HAVE_SIGSET_T -  memset(&(attr->sigmask), 0, sizeof(sigset_t)); +  memset(&(attr_result->sigmask), 0, sizeof(sigset_t));  #endif /* HAVE_SIGSET_T */    /* Priority uses Win32 priority values. */ -  attr->priority = THREAD_PRIORITY_NORMAL; +  attr_result->priority = THREAD_PRIORITY_NORMAL; -  attr->valid = _PTHREAD_ATTR_VALID; +  attr_result->valid = _PTHREAD_ATTR_VALID; + +  *attr = attr_result;    return 0;  }  int  pthread_attr_destroy(pthread_attr_t *attr) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      Destroys a thread attributes object. +      * +      * PARAMETERS +      *      attr +      *              pointer to an instance of pthread_attr_t +      * +      * +      * DESCRIPTION +      *      Destroys a thread attributes object. +      * +      *      NOTES: +      *              1)      Does not affect threads created with 'attr'. +      * +      * RESULTS +      *              0               successfully destroyed attr, +      *              EINVAL          'attr' is invalid. +      * +      * ------------------------------------------------------ +      */  {    if (is_attr(attr) != 0)      {        return EINVAL;      } -  /* Set the attribute object to a specific invalid value. */ -  attr->valid = 0; +  /* +   * Set the attribute object to a specific invalid value. +   */ +  (*attr)->valid = 0; +  free (*attr); +  *attr = NULL;    return 0;  } @@ -127,19 +375,89 @@ pthread_attr_destroy(pthread_attr_t *attr)  int  pthread_attr_getdetachstate(const pthread_attr_t *attr,  			    int *detachstate) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function determines whether threads created with +      *      'attr' will run detached. +      * +      * PARAMETERS +      *      attr +      *              pointer to an instance of pthread_attr_t +      * +      *      detachstate +      *              pointer to an integer into which is returned one +      *              of: +      * +      *              PTHREAD_CREATE_JOINABLE +      *                              Thread ID is valid, must be joined +      * +      *              PTHREAD_CREATE_DETACHED +      *                              Thread ID is invalid, cannot be joined, +      *                              canceled, or modified +      * +      * +      * DESCRIPTION +      *      This function determines whether threads created with +      *      'attr' will run detached. +      * +      *      NOTES: +      *              1)      You cannot join or cancel detached threads. +      * +      * RESULTS +      *              0               successfully retrieved detach state, +      *              EINVAL          'attr' is invalid +      * +      * ------------------------------------------------------ +      */  {    if (is_attr(attr) != 0 || detachstate == NULL)      { +      *detachstate = PTHREAD_CREATE_DETACHED;        return EINVAL;      } -  *detachstate = attr->detachedstate; +  *detachstate = (*attr)->detachstate;    return 0;  }  int  pthread_attr_setdetachstate(pthread_attr_t *attr,  			    int detachstate) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function specifies whether threads created with +      *      'attr' will run detached. +      * +      * PARAMETERS +      *      attr +      *              pointer to an instance of pthread_attr_t +      * +      *      detachstate +      *              an integer containing one of: +      * +      *              PTHREAD_CREATE_JOINABLE +      *                              Thread ID is valid, must be joined +      * +      *              PTHREAD_CREATE_DETACHED +      *                              Thread ID is invalid, cannot be joined, +      *                              canceled, or modified +      * +      * +      * DESCRIPTION +      *      This function specifies whether threads created with +      *      'attr' will run detached. +      * +      *      NOTES: +      *              1)      You cannot join or cancel detached threads. +      * +      * RESULTS +      *              0               successfully set detach state, +      *              EINVAL          'attr' or 'detachstate' is invalid +      * +      * ------------------------------------------------------ +      */  {    if (is_attr(attr) != 0)      { @@ -152,6 +470,10 @@ pthread_attr_setdetachstate(pthread_attr_t *attr,        return EINVAL;      } -  attr->detachedstate = detachstate; +  (*attr)->detachstate = detachstate;    return 0;  } + + + + diff --git a/buildlib.bat b/buildlib.bat index e8a674e..5e2e1c8 100644 --- a/buildlib.bat +++ b/buildlib.bat @@ -16,5 +16,8 @@ cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c sched.  cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c signal.c  cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c sync.c  cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c tsd.c +cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c semaphore.c  cl /LD /Zi *.obj /Fepthread.dll /link /nodefaultlib:libcmt /implib:pthread.lib msvcrt.lib /def:pthread.def + + @@ -12,6 +12,139 @@  #include "pthread.h"  #include "implement.h" +/* + * Code contributed by John E. Bossom <JEB>. + */ + +_pthread_cleanup_t * +_pthread_pop_cleanup (int execute) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function pops the most recently pushed cleanup +      *      handler. If execute is nonzero, then the cleanup handler +      *      is executed if non-null. +      * +      * PARAMETERS +      *      execute +      *              if nonzero, execute the cleanup handler +      * +      * +      * DESCRIPTION +      *      This function pops the most recently pushed cleanup +      *      handler. If execute is nonzero, then the cleanup handler +      *      is executed if non-null. +      *      NOTE: specify 'execute' as nonzero to avoid duplication +      *                of common cleanup code. +      * +      * RESULTS +      *              N/A +      * +      * ------------------------------------------------------ +      */ +{ +  _pthread_cleanup_t *cleanup; +   +  cleanup = pthread_getspecific (_pthread_cleanupKey); + +  if (cleanup != NULL) +    { +      if (execute && (cleanup->routine != NULL)) +        { + +#ifdef _WIN32 + +          __try +          { +            /* +             * Run the caller's cleanup routine. +             */ +            (*cleanup->routine) (cleanup->arg); +          } +          __except (EXCEPTION_EXECUTE_HANDLER) +          { +            /* +             * A system unexpected exception had occurred +             * running the user's cleanup routine. +             * We get control back within this block. +             */ +          } +        } + +#else + +      /* +       * Run the caller's cleanup routine. +       */ +      (*cleanup->routine) (cleanup->arg); + +#endif /* _WIN32 */ + +      pthread_setspecific (_pthread_cleanupKey, cleanup->prev); +    } + +  return (cleanup); + +}                               /* _pthread_pop_cleanup */ + + +void +_pthread_push_cleanup (_pthread_cleanup_t * cleanup, +		      void (*routine) (void *), +		      void *arg) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function pushes a new cleanup handler onto the thread's stack +      *      of cleanup handlers. Each cleanup handler pushed onto the stack is +      *      popped and invoked with the argument 'arg' when +      *              a) the thread exits by calling 'pthread_exit', +      *              b) when the thread acts on a cancellation request, +      *              c) or when the thrad calls pthread_cleanup_pop with a nonzero +      *                 'execute' argument +      * +      * PARAMETERS +      *      cleanup +      *              a pointer to an instance of pthread_cleanup_t, +      * +      *      routine +      *              pointer to a cleanup handler, +      * +      *      arg +      *              parameter to be passed to the cleanup handler +      * +      * +      * DESCRIPTION +      *      This function pushes a new cleanup handler onto the thread's stack +      *      of cleanup handlers. Each cleanup handler pushed onto the stack is +      *      popped and invoked with the argument 'arg' when +      *              a) the thread exits by calling 'pthread_exit', +      *              b) when the thread acts on a cancellation request, +      *              c) or when the thrad calls pthread_cleanup_pop with a nonzero +      *                 'execute' argument +      *      NOTE: pthread_push_cleanup, pthread_pop_cleanup must be paired +      *                in the same lexical scope. +      * +      * RESULTS +      *              pthread_cleanup_t * +      *                              pointer to the previous cleanup +      * +      * ------------------------------------------------------ +      */ +{ +  cleanup->routine = routine; +  cleanup->arg = arg; +  cleanup->prev = pthread_getspecific (_pthread_cleanupKey); + +  pthread_setspecific (_pthread_cleanupKey, (void *) cleanup); + +}                               /* _pthread_push_cleanup */ + +/* </JEB> */ + + +#if 0 /* Pre Bossom */ +  int  _pthread_handler_push(int stack,  		      int poporder, @@ -214,3 +347,5 @@ _pthread_destructor_run_all()  	break;      }  } + +#endif /* Pre Bossom */ @@ -90,7 +90,6 @@ pthread_create (pthread_t * tid,      {        stackSize = (*attr)->stacksize;        thread->detachState = (*attr)->detachstate; -      }    else      { @@ -109,7 +108,7 @@ pthread_create (pthread_t * tid,      _beginthreadex (  		     (void *) NULL,	/* No security info             */  		     (unsigned) stackSize,	/* default stack size   */ -		     (unsigned (__stdcall *) (void *)) threadStart, +		     (unsigned (__stdcall *) (void *)) _pthread_threadStart,  		     parms,  		     (unsigned) run ? 0 : CREATE_SUSPENDED,  		     (unsigned *) &(thread->thread)); @@ -130,7 +129,7 @@ FAIL0:    if (result != 0)      { -      threadDestroy (thread); +      _pthread_threadDestroy (thread);        thread = NULL;        if (parms != NULL) @@ -235,7 +234,7 @@ pthread_create(pthread_t *thread,  	      attr_copy->stacksize = PTHREAD_STACK_MIN;  	    } -	  attr_copy->detachedstate = attr->detachedstate; +	  attr_copy->detachstate = attr->detachstate;  	  attr_copy->priority = attr->priority;  #if HAVE_SIGSET_T @@ -69,10 +69,6 @@ DllMain (  	if (_pthread_processInitialized)  	  { -#if defined( KLUDGE ) -	    _pthread_cleanupStack (); -#endif /* KLUDGE */ -  	    self = (pthread_t) pthread_getspecific (_pthread_selfThreadKey);  	    /* @@ -5,12 +5,12 @@   * Implementation of fork() for POSIX threads.   */ -/* FIXME! */ -#define ENOMEM 0  #include "pthread.h"  #include "implement.h" +#if 0 /* Pre Bossom */ +  int  pthread_atfork(void (*prepare)(void),  	       void (*parent)(void), @@ -139,3 +139,5 @@ fork()  }  #endif /* HAVE_PID_T && HAVE_FORK */ + +#endif /* Pre Bossom */ diff --git a/implement.h b/implement.h index 523f475..c3be637 100644 --- a/implement.h +++ b/implement.h @@ -13,107 +13,6 @@   * 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; @@ -8,6 +8,7 @@  #include <errno.h>  #include "pthread.h" +#include "implement.h"  int  pthread_once(pthread_once_t *once_control, @@ -155,7 +155,7 @@ _pthread_threadDestroy (pthread_t thread)    if (thread != NULL)      { -      callUserDestroyRoutines (thread); +      _pthread_callUserDestroyRoutines (thread);        if (thread->cancelEvent != NULL)  	{ diff --git a/pthread.def b/pthread.def index 63687f5..df689cc 100644 --- a/pthread.def +++ b/pthread.def @@ -1,12 +1,12 @@  ; pthread.def -; Last updated: $Date: 1998/10/04 23:01:59 $ +; Last updated: $Date: 1998/12/28 23:01:11 $  ; Currently unimplemented functions are commented out.  LIBRARY pthread  EXPORTS -pthread_atfork +;pthread_atfork  pthread_attr_destroy  pthread_attr_getdetachstate  ;pthread_attr_getinheritsched @@ -234,7 +234,7 @@ struct timespec {  #include <semaphore.h> -#include <sched.h> +/* #include <sched.h> /**/  #ifdef __cplusplus @@ -397,7 +397,7 @@ extern "C"    typedef struct pthread_t_ *pthread_t; -  typedef struct pthread_attr_t_ pthread_attr_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; @@ -483,6 +483,126 @@ extern "C"  /*   * ====================   * ==================== + * Opaque Structure Definitions + * ==================== + * ==================== + */ + +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; +}; + + +/*  + * Special value to mark attribute objects as valid. + */ +#define _PTHREAD_ATTR_VALID 0xC4C0FFEE + +struct pthread_attr_t_ { +  long valid; +  void *stackaddr; +  size_t stacksize; +  int detachstate; +  int priority; +#if HAVE_SIGSET_T +  sigset_t sigmask; +#endif /* HAVE_SIGSET_T */ +}; + + +struct pthread_mutex_t_ { +	int valid; +	CRITICAL_SECTION cs; +  }; + + +struct pthread_mutexattr_t_ { +  int pshared; +}; + + +struct pthread_key_t_ { +  DWORD key; +  void (*destructor) (void *); +  pthread_mutex_t threadsLock; +  void *threads; +}; + + +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; +}; + + +/* + * ==================== + * ====================   * Scheduling   * ====================   * ==================== @@ -510,28 +630,31 @@ extern "C"   *   WIN32 SEH or C++   */ -#ifndef __cplusplus +  typedef struct _pthread_cleanup_t _pthread_cleanup_t; -/* - * C implementation of PThreads cancel cleanup - */ -  typedef struct pthread_cleanup_t pthread_cleanup_t; - -  struct pthread_cleanup_t +  struct _pthread_cleanup_t      {        void (*routine) (void *);        void *arg; -      pthread_cleanup_t *prev; +#if !defined(__cplusplus) +      _pthread_cleanup_t *prev; +#endif      }; +#ifndef __cplusplus + +/* + * C implementation of PThreads cancel cleanup + */ +  #define pthread_cleanup_push( _rout, _arg ) \  	{ \ -	    pthread_cleanup_t	cleanup; \ +	    _pthread_cleanup_t	_cleanup; \              \ -	    pthread_push_cleanup( &cleanup, (_rout), (_arg) ); \ +	    _pthread_push_cleanup( &_cleanup, (_rout), (_arg) ); \  #define pthread_cleanup_pop( _execute ) \ -	    (void) pthread_pop_cleanup( _execute ); \ +	    (void) _pthread_pop_cleanup( _execute ); \  	}  #else /* !__cplusplus */ @@ -543,7 +666,7 @@ extern "C"  #define pthread_cleanup_push( _rout, _arg ) \  	{ \ -	    pthread_cleanup_t	_cleanup; \ +	    _pthread_cleanup_t	_cleanup; \  	    \              _cleanup.routine	= (_rout); \  	    _cleanup.arg	= (_arg); \ @@ -571,7 +694,7 @@ extern "C"  #define pthread_cleanup_push( _rout, _arg ) \  	{ \ -	    pthread_cleanup_t	_cleanup; \ +	    _pthread_cleanup_t	_cleanup; \  	    \              _cleanup.routine	= (_rout); \  	    _cleanup.arg	= (_arg); \ @@ -652,11 +775,13 @@ pthread_t pthread_self (void);  int pthread_cancel (pthread_t thread); -pthread_cleanup_t *pthread_pop_cleanup (int execute); +#ifndef __cplusplus +_pthread_cleanup_t *_pthread_pop_cleanup (int execute); -void pthread_push_cleanup (pthread_cleanup_t * cleanup, +void _pthread_push_cleanup (_pthread_cleanup_t * cleanup,  			   void (*routine) (void *),  			   void *arg); +#endif /* !__cplusplus */  int pthread_setcancelstate (int state,  			    int *oldstate); @@ -817,3 +942,4 @@ int pthreadCancelableWait (HANDLE waitHandle);  }				/* End of extern "C" */  #endif				/* __cplusplus */ +#endif /* PTHREAD_H */ @@ -15,7 +15,9 @@  static int  is_attr(const pthread_attr_t *attr)  { -  return (attr == NULL || attr->valid != _PTHREAD_ATTR_VALID) ? 1 : 0; +  return (attr == NULL ||  +	  *attr == NULL ||  +	  (*attr)->valid != _PTHREAD_ATTR_VALID) ? 1 : 0;  }  int @@ -27,11 +29,12 @@ pthread_attr_setschedparam(pthread_attr_t *attr,        return EINVAL;      } -  attr->priority = param->sched_priority; +  (*attr)->priority = param->sched_priority;    return 0;  } -int pthread_attr_getschedparam(const pthread_attr_t *attr, +int  +pthread_attr_getschedparam(const pthread_attr_t *attr,  			       struct sched_param *param)  {    if (is_attr(attr) != 0 || param == NULL) @@ -39,7 +42,7 @@ int pthread_attr_getschedparam(const pthread_attr_t *attr,        return EINVAL;      } -  param->sched_priority = attr->priority; +  param->sched_priority = (*attr)->priority;    return 0;  } @@ -47,7 +50,7 @@ int pthread_setschedparam(pthread_t thread, int policy,  			  const struct sched_param *param)  {    /* Validate the thread id. */ -  if (_PTHREAD_VALID(thread) < 0) +  if (thread == NULL || thread->threadH == 0)      {        return EINVAL;      } @@ -72,7 +75,8 @@ int pthread_setschedparam(pthread_t thread, int policy,      }    /* This is practically guaranteed to return TRUE. */ -  (void) SetThreadPriority(thread->win32handle, param->sched_priority); +  (void) SetThreadPriority(thread->threadH, param->sched_priority); +    return 0;  } @@ -82,7 +86,7 @@ int pthread_getschedparam(pthread_t thread, int *policy,    int prio;    /* Validate the thread id. */ -  if (_PTHREAD_VALID(thread) != 0) +  if (thread == NULL || thread->threadH == 0)      {        return EINVAL;      } @@ -97,7 +101,7 @@ int pthread_getschedparam(pthread_t thread, int *policy,    *policy = SCHED_OTHER;    /* Fill out the sched_param structure. */ -  prio = GetThreadPriority(thread->win32handle); +  prio = GetThreadPriority(thread->threadH);    if (prio == THREAD_PRIORITY_ERROR_RETURN)      {        return EINVAL; diff --git a/semaphore.c b/semaphore.c new file mode 100644 index 0000000..04e99f5 --- /dev/null +++ b/semaphore.c @@ -0,0 +1,257 @@ +/* + * ------------------------------------------------------------- + * + * $Header: /cvs/pthreads-win32/pthreads/semaphore.c,v 1.1.2.1 1998/12/28 23:01:14 rpj Exp $ + * + * Module: semaphore.c + * + * Purpose: + *      Semaphores aren't actually part of the PThreads standard. + *      They are defined by the POSIX Standard: + * + *              POSIX 1003.1b-1993      (POSIX.1b) + * + *      They are supposed to follow the older UNIX convention for + *      reporting errors. That is, on failure they are supposed + *      to return a value of -1 and store the appropriate error + *      number into 'errno'. + *      HOWEVER,errno cannot be modified in a multithreaded + *      program on WIN32; therefore, the value is returned as + *      the function value. + *      It is recommended that you compare for zero (0) for success + *      instead of -1 for failure when checking the status of + *      these functions. + * + * Contents: + *              Public Methods                    Author + *              --------------                    ------ + *              sem_init                          John E. Bossom  Mar 1998 + *              sem_destroy                       John E. Bossom  Mar 1998 + *              sem_trywait                       John E. Bossom  Mar 1998 + *              sem_wait                          John E. Bossom  Mar 1998 + *              sem_post                          John E. Bossom  Mar 1998 + * + *              Private Methods + *              --------------- + * + * ------------------------------------------------------------- + */ +#include <pthread.h> +#include <windows.h> +#include <process.h> +#include <errno.h> +#include <string.h> + +#include "semaphore.h" + + + +int +sem_init (sem_t * sem, int pshared, unsigned int 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 +      * +      *      pshared +      *              if zero, this semaphore may only be shared between +      *              threads in the same process. +      *              if nonzero, the semaphore can be shared between +      *              processes +      * +      *      value +      *              initial value of the semaphore counter +      * +      * 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; + +  if (pshared != 0) +    { +      /* +       * Creating a semaphore that can be shared between +       * processes +       */ +      result = EPERM; + +    } +  else +    { +      /* +       * NOTE: Taking advantage of the fact that +       *               sem_t is a simple structure with one entry; +       *               We don't have to allocate it... +       */ +      *sem = CreateSemaphore ( +			       0, +			       value, +			       0x7FFFFFF, +			       NULL); + +      if (*sem == 0) +	{ +	  result = ENOSPC; +	} +    } + +  return (result); + +}				/* sem_init */ + + +int +sem_destroy (sem_t * sem) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function destroys an unnamed semaphore. +      * +      * PARAMETERS +      *      sem +      *              pointer to an instance of sem_t +      * +      * DESCRIPTION +      *      This function destroys an unnamed semaphore. +      * +      * RESULTS +      *              0                       successfully destroyed semaphore, +      *              EINVAL          'sem' is not a valid semaphore, +      *              ENOSYS          semaphores are not supported, +      *              EBUSY           threads (or processes) are currently +      *                                      blocked on 'sem' +      * +      * ------------------------------------------------------ +      */ +{ +  return ((sem == NULL) +	  ? EINVAL +	  : (CloseHandle (*sem) +	     ? 0 +	     : EINVAL)); + +}				/* sem_destroy */ + + +int +sem_trywait (sem_t * sem) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function tries to wait on a semaphore. +      * +      * PARAMETERS +      *      sem +      *              pointer to an instance of sem_t +      * +      * DESCRIPTION +      *      This function tries to wait on a semaphore. If the +      *      semaphore value is greater than zero, it decreases +      *      its value by one. If the semaphore value is zero, then +      *      this function returns immediately with the error EAGAIN +      * +      * RESULTS +      *              0                       successfully destroyed semaphore, +      *              EAGAIN          the semaphore was already locked, +      *              EINVAL          'sem' is not a valid semaphore, +      *              ENOSYS          semaphores are not supported, +      *              EINTR           the function was interrupted by a signal, +      *              EDEADLK         a deadlock condition was detected. +      * +      * ------------------------------------------------------ +      */ +{ +  return ((sem == NULL) +	  ? EINVAL +	  : ((WaitForSingleObject (*sem, 0) == WAIT_TIMEOUT) +	     ? EAGAIN +	     : 0)); + +}				/* sem_trywait */ + + +int +sem_wait (sem_t * sem) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function  waits on a semaphore. +      * +      * PARAMETERS +      *      sem +      *              pointer to an instance of sem_t +      * +      * DESCRIPTION +      *      This function waits on a semaphore. If the +      *      semaphore value is greater than zero, it decreases +      *      its value by one. If the semaphore value is zero, then +      *      the calling thread (or process) is blocked until it can +      *      successfully decrease the value or until interrupted by +      *      a signal. +      * +      * RESULTS +      *              0                       successfully destroyed semaphore, +      *              EINVAL          'sem' is not a valid semaphore, +      *              ENOSYS          semaphores are not supported, +      *              EINTR           the function was interrupted by a signal, +      *              EDEADLK         a deadlock condition was detected. +      * +      * ------------------------------------------------------ +      */ +{ + +  return ((sem == NULL) +	  ? EINVAL +	  : pthreadCancelableWait (*sem) +    ); + +}				/* sem_wait */ + + +int +sem_post (sem_t * sem) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function posts a wakeup to a semaphore. +      * +      * PARAMETERS +      *      sem +      *              pointer to an instance of sem_t +      * +      * DESCRIPTION +      *      This function posts a wakeup to a semaphore. If there +      *      are waiting threads (or processes), on is awakened; +      *      otherwise, the semaphore value is incremented by one. +      * +      * RESULTS +      *              0                       successfully destroyed semaphore, +      *              EINVAL          'sem' is not a valid semaphore, +      *              ENOSYS          semaphores are not supported, +      * +      * ------------------------------------------------------ +      */ +{ +  return ((sem == NULL) +	  ? EINVAL +	  : (ReleaseSemaphore (*sem, 1, 0) +	     ? 0 +	     : EINVAL)); + +}				/* sem_post */ diff --git a/semaphore.h b/semaphore.h new file mode 100644 index 0000000..7b9d352 --- /dev/null +++ b/semaphore.h @@ -0,0 +1,65 @@ +/* + * ------------------------------------------------------------- + * + * $Header: /cvs/pthreads-win32/pthreads/semaphore.h,v 1.1.2.1 1998/12/28 23:01:15 rpj Exp $ + * + * Module: semaphore.h + * + * Purpose: + *      Semaphores aren't actually part of the PThreads standard. + *      They are defined by the POSIX Standard: + * + *              POSIX 1003.1b-1993      (POSIX.1b) + * + *      They are supposed to follow the older UNIX convention for + *      reporting errors. That is, on failure they are supposed + *      to return a value of -1 and store the appropriate error + *      number into 'errno'. + *      HOWEVER,errno cannot be modified in a multithreaded + *      program on WIN32; therefore, the value is returned as + *      the function value. + *      It is recommended that you compare for zero (0) for success + *      instead of -1 for failure when checking the status of + *      these functions. + * + * Disclaimer: + *      This software is provided "as is". + * + *      The author makes no warranty or representation, either + *      express or implied, with respect to this software, its + *      quality, performance, merchantability, or fitness for a + *      particular purpose. In no event will the author be + *      liable for direct, indirect, special, incidental, or + *      consequential damages arising out of the use or inability + *      to use the software. + * + * ------------------------------------------------------------- + */ +#if !defined( SEMAPHORE_H ) +#define SEMAPHORE_H + +#include <process.h> +#include <errno.h> + +#ifdef __cplusplus +extern "C" +{ +#endif				/* __cplusplus */ + +typedef HANDLE sem_t; + +int sem_init (sem_t * sem, int pshared, unsigned int value); + +int sem_destroy (sem_t * sem); + +int sem_trywait (sem_t * sem); + +int sem_wait (sem_t * sem); + +int sem_post (sem_t * sem); + +#ifdef __cplusplus +}				/* End of extern "C" */ +#endif				/* __cplusplus */ + +#endif				/* !SEMAPHORE_H */ @@ -10,6 +10,9 @@   * Code contributed by John E. Bossom <JEB>.   */ +#include "pthread.h" +#include "implement.h" +  int  pthread_detach (pthread_t tid)       /* @@ -112,7 +115,7 @@ pthread_join (pthread_t thread, void **value_ptr)  	}        else  	{ -	  threadDestroy (thread); +	  _pthread_threadDestroy (thread);  	}      } @@ -189,7 +189,7 @@ pthread_key_delete (pthread_key_t key)                    pthread_mutex_unlock (&(assoc->lock)); -                  tkAssocDestroy (assoc); +                  _pthread_tkAssocDestroy (assoc);                    assoc = next;                  } @@ -304,7 +304,7 @@ pthread_setspecific (pthread_key_t key, const void *value)             * create an association if not found             */            result = (assoc == NULL) -            ? tkAssocCreate (&assoc, self, key) +            ? _pthread_tkAssocCreate (&assoc, self, key)              : 0;          }        else | 
