diff options
| -rw-r--r-- | ANNOUNCE | 62 | ||||
| -rw-r--r-- | ChangeLog | 44 | ||||
| -rw-r--r-- | Makefile.in | 4 | ||||
| -rw-r--r-- | condvar.c | 17 | ||||
| -rw-r--r-- | create.c | 6 | ||||
| -rw-r--r-- | errno.c | 87 | ||||
| -rw-r--r-- | implement.h | 137 | ||||
| -rw-r--r-- | private.c | 101 | ||||
| -rw-r--r-- | pthread.def | 13 | ||||
| -rw-r--r-- | pthread.h | 177 | ||||
| -rw-r--r-- | sched.c | 34 | ||||
| -rw-r--r-- | sched.h | 73 | ||||
| -rw-r--r-- | semaphore.c | 215 | ||||
| -rw-r--r-- | semaphore.h | 62 | ||||
| -rw-r--r-- | tests/ChangeLog | 9 | ||||
| -rw-r--r-- | tests/condvar3.c | 2 | ||||
| -rw-r--r-- | tests/runall.bat | 4 | ||||
| -rw-r--r-- | tests/runtest.bat | 55 | ||||
| -rw-r--r-- | tests/tsd1.c | 3 | 
19 files changed, 756 insertions, 349 deletions
| @@ -1,24 +1,18 @@ -                PTHREADS-WIN32 SNAPSHOT 1999-03-16 +                PTHREADS-WIN32 SNAPSHOT 1999-04-04                  ----------------------------------         Web Site: http://sourceware.cygnus.com/pthreads-win32/          Coordinator: Ross Johnson <rpj@ise.canberra.edu.au> -We are pleased to announce the availability of Pthreads-win32, an -Open Source Software (OSS) implementation of the Threads component -of the POSIX 1003.1c 1996 Standard for Microsoft's Win32 -environment. +We are pleased to announce the availability of a new snapshot of +Pthreads-win32, an Open Source Software (OSS) implementation of the +Threads component of the POSIX 1003.1c 1995 Standard for Microsoft's +Win32 environment. Some functions from POSIX 1003.1b are supported.  Pthreads-win32 is free software, distributed under the GNU Library  General Public License (LGPL). -This is the first general announcement of the library in workable -form. We expect it to be stable in the real world having passed it's -own test suite, however, if you do find bugs in the library please -let us know either via the mailing list (see below), or by emailing -the coordinator directly (see above). -  Pthreads-win32 is based substantially on a Win32 pthreads  implementation contributed by John E. Bossom <jebossom@cognos.com>. @@ -26,17 +20,35 @@ Please see the 'Acknowledgements' section at the end of this  announcement for the list of contributors. +Change Summary +-------------- + +Some POSIX 1b functions which were internally supported are now +available as exported functions: + +	sem_init +	sem_destroy +	sem_wait +	sem_trywait +	sem_post +	sched_yield +	sched_get_priority_min +	sched_get_priority_max + +Some minor bugs have been fixed. See the ChangeLog file for details. + +  Level of standards conformance  ------------------------------ -The following POSIX 1003.1c 1996 options are defined: +The following POSIX 1003.1c 1995 options are defined:        _POSIX_THREADS        _POSIX_THREAD_SAFE_FUNCTIONS        _POSIX_THREAD_ATTR_STACKSIZE -The following POSIX 1003.1c 1996 options are not defined: +The following POSIX 1003.1c 1995 options are not defined:        _POSIX_THREAD_ATTR_STACKADDR        _POSIX_THREAD_PRIORITY_SCHEDULING @@ -112,15 +124,25 @@ The following functions are implemented:        pthread_cond_broadcast          --------------------------- +      Semaphores +      --------------------------- +      sem_init               (POSIX 1b) +      sem_destroy            (POSIX 1b) +      sem_post               (POSIX 1b) +      sem_wait               (POSIX 1b) +      sem_trywait            (POSIX 1b) + +      ---------------------------        RealTime Scheduling        ---------------------------        pthread_attr_getschedparam          pthread_attr_setschedparam          pthread_getschedparam        pthread_setschedparam -      sched_get_priority_max -      sched_get_priority_min -       +      sched_get_priority_max (POSIX 1b) +      sched_get_priority_min (POSIX 1b) +      sched_yield            (POSIX 1b) +        ---------------------------        Signals        --------------------------- @@ -241,9 +263,11 @@ against the export library libpthread32.a built under Mingw32  together with the version of pthread.dll built with MSVC.  Cygwin: (http://sourceware.cygnus.com/cygwin/) -Cygwin does not have thread-safe libraries and should not be used -for threaded applications. -       +Cygwin aims to provide a complete POSIX environment on top of Win32, including +threads. When this is complete, developers using Cygwin will not need +pthreads-win32. At this time, Cygwin has preliminary support for multithreaded +development, however, this is not turned on by default. +  Generally:  For convenience, the following pre-built files can be downloaded from  the FTP site: @@ -1,3 +1,47 @@ +Sun Apr  4 11:05:57 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au> + +	* sched.c (sched.h): Include. + +	* sched.h: New file for POSIX 1b scheduling. + +	* pthread.h: Move opaque structures to implement.h; move sched_* +	prototypes out and into sched.h. + +	* implement.h: Add opaque structures from pthread.h. + +	* sched.c (sched_yield): New function. + +	* condvar.c (_pthread_sem_*): Rename to sem_*; except for +	_pthread_sem_timedwait which is an private function. + +Sat Apr  3 23:28:00 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au> + +	* Makefile.in (OBJS): Add errno.o. + +Fri Apr  2 11:08:50 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au> + +	* implement.h (_pthread_sem_*): Remove prototypes now defined in +	semaphore.h. + +	* pthread.h (sempahore.h): Include. + +	* semaphore.h: New file for POSIX 1b semaphores. + +	* pthread.h (_pthread_sem_t): Change to sem_t.  + +	* semaphore.c (_pthread_sem_*): Change to sem_*; these functions +	will be exported from the library; set errno on error. +	- John Bossom <jebossom@cognos.com> +	(_pthread_sem_timedwait): Moved to private.c. + +	* private.c (_pthread_sem_timedwait): Moved from semaphore.c; +	set errno on error. + +	* errno.c (_errno): New file. New function. +	- John Bossom + +	* pthread.h (pthread_t_): Add per-thread errno element. +  Fri Mar 26 14:11:45 1999  Ross Johnson  <rpj@swan.canberra.edu.au>  	* semaphore.c (_pthread_sem_timedwait): Check for negative diff --git a/Makefile.in b/Makefile.in index 55228a9..2844862 100644 --- a/Makefile.in +++ b/Makefile.in @@ -34,11 +34,11 @@ CFLAGS	= $(OPT) -I. -DHAVE_CONFIG_H -Wall  ## Cygwin G++  #CFLAGS	= $(OPT) -fhandle-exceptions -I. -DHAVE_CONFIG_H -Wall -OBJS	= attr.o cancel.o cleanup.o condvar.o create.o dll.o \ +OBJS	= attr.o cancel.o cleanup.o condvar.o create.o dll.o errno.o \  	  exit.o fork.o global.o misc.o mutex.o private.o sched.o \  	  semaphore.o signal.o sync.o tsd.o -INCL	= implement.h pthread.h windows.h +INCL	= implement.h semaphore.h pthread.h windows.h  DLL     = pthread.dll @@ -375,7 +375,7 @@ pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)    cv->waiters = 0;    cv->wasBroadcast = FALSE; -  if (_pthread_sem_init (&(cv->sema), 0, 0) != 0) +  if (sem_init (&(cv->sema), 0, 0) != 0)      {        goto FAIL0;      } @@ -408,7 +408,7 @@ FAIL2:    (void) pthread_mutex_destroy (&(cv->waitersLock));  FAIL1: -  (void) _pthread_sem_destroy (&(cv->sema)); +  (void) sem_destroy (&(cv->sema));  FAIL0:  DONE: @@ -468,7 +468,7 @@ pthread_cond_destroy (pthread_cond_t * cond)  	  return EBUSY;  	} -      (void) _pthread_sem_destroy (&(cv->sema)); +      (void) sem_destroy (&(cv->sema));        (void) pthread_mutex_destroy (&(cv->waitersLock));        (void) CloseHandle (cv->waitersDone); @@ -522,7 +522,7 @@ cond_timedwait (pthread_cond_t * cond,     * 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 _pthread_sem_wait since that will deadlock other calls +   * call to sem_wait since that will deadlock other calls     * to pthread_cond_signal     */    if ((result = pthread_mutex_unlock (mutex)) == 0) @@ -541,7 +541,10 @@ cond_timedwait (pthread_cond_t * cond,         */        pthread_cleanup_push (pthread_mutex_lock, mutex); -      result = _pthread_sem_timedwait (&(cv->sema), abstime); +      if (_pthread_sem_timedwait (&(cv->sema), abstime) == -1) +	{ +	  result = errno; +	}        pthread_cleanup_pop (0);      } @@ -772,7 +775,7 @@ pthread_cond_signal (pthread_cond_t * cond)     */    if (cv->waiters > 0)      { -      result = _pthread_sem_post (&(cv->sema)); +      result = sem_post (&(cv->sema));      }    return (result); @@ -843,7 +846,7 @@ pthread_cond_broadcast (pthread_cond_t * cond)     */    for (i = cv->waiters; i > 0 && result == 0; i--)      { -      result = _pthread_sem_post (&(cv->sema)); +      result = sem_post (&(cv->sema));      }    if (cv->waiters > 0 && result == 0) @@ -27,10 +27,6 @@  #include "pthread.h"  #include "implement.h" -/* - * Code contributed by John E. Bossom <JEB>. - */ -  int  pthread_create (pthread_t * tid,  		const pthread_attr_t * attr, @@ -168,5 +164,3 @@ FAIL0:  }				/* pthread_create */ -/* </JEB> */ - @@ -0,0 +1,87 @@ +/* + * errno.c + * + * Description: + * This translation unit implements routines associated with spawning a new + * thread. + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright (C) 1998 + * + * 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 + */ + +#if defined( _REENTRANT ) || defined( _MT ) + +#include "pthread.h" +#include "implement.h" + +static int reallyBad    = ENOMEM; + +/* + * Re-entrant errno. + * + * Each thread has it's own errno variable in pthread_t. + * + * The benefit of using the pthread_t structure + * instead of another TSD key is TSD keys are limited + * on Win32 to 64 per process. Secondly, to implement + * it properly without using pthread_t you'd need + * to dynamically allocate an int on starting the thread + * and store it manually into TLS and then ensure that you free + * it on thread termination. We get all that for free + * by simply storing the errno on the pthread_t structure. + * + * Relies on the following being defined in errno.h: + * (true for MSVC and Mingw32 I think) + * + * #if defined( _REENTRANT ) || defined( _MT ) + * #define errno *_errno() + *  + * int *_errno( void ); + * #else + * extern int errno; + * #endif /* _REENTRANT */ + * + */ + +int * _errno( void ) +{ +  pthread_t       *self; +  int             *result; +         +  if( ( self = pthread_self() ) == NULL ) +    { +      /* +       * Yikes! unable to allocate a thread! +       * Throw an exception? return an error? +       */ +      result = &reallyBad; +    } +  else +    { +      result = &(self->ptErrno); +    } + +  return( result ); + +} /* _errno */ + +#else + +#error "errno: Not thread-safe." + +#endif /* _REENTRANT || _MT */ diff --git a/implement.h b/implement.h index 7740e0c..6151ce4 100644 --- a/implement.h +++ b/implement.h @@ -27,11 +27,111 @@  #ifndef _IMPLEMENT_H  #define _IMPLEMENT_H +#include <semaphore.h> + +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 ptErrno; +  int detachState; +  int cancelState; +  int cancelType; +  HANDLE cancelEvent; +#if HAVE_SIGSET_T +  sigset_t sigmask; +#endif /* HAVE_SIGSET_T */ +  int implicit:1; +  void *keys; +}; + + +/*  + * Special value to mark attribute objects as valid. + */ +#define _PTHREAD_ATTR_VALID ((unsigned long) 0xC4C0FFEE) + +struct pthread_attr_t_ { +  unsigned long valid; +  void *stackaddr; +  size_t stacksize; +  int detachstate; +  int priority; +#if HAVE_SIGSET_T +  sigset_t sigmask; +#endif /* HAVE_SIGSET_T */ +}; + + +/* + * ==================== + * ==================== + * Mutexes and Condition Variables + * ==================== + * ==================== + */ + +#define _PTHREAD_OBJECT_AUTO_INIT ((void *) -1) +#define _PTHREAD_OBJECT_INVALID   NULL + +struct pthread_mutex_t_ { +  HANDLE mutex; +  CRITICAL_SECTION cs; +}; + + +struct pthread_mutexattr_t_ { +  int pshared; +  int forcecs; +}; + + +struct pthread_key_t_ { +  DWORD key; +  void (*destructor) (void *); +  pthread_mutex_t threadsLock; +  void *threads; +}; +  typedef struct ThreadParms ThreadParms;  typedef struct ThreadKeyAssoc ThreadKeyAssoc; -  struct ThreadParms {    pthread_t tid;    void *(*start) (void *); @@ -39,6 +139,27 @@ struct ThreadParms {  }; +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 ThreadKeyAssoc {    /*     * Purpose: @@ -198,21 +319,9 @@ int _pthread_tkAssocCreate (ThreadKeyAssoc ** assocP,  void _pthread_tkAssocDestroy (ThreadKeyAssoc * assoc); -int _pthread_sem_init (_pthread_sem_t * sem,  -		       int pshared,  -		       unsigned int value); - -int _pthread_sem_destroy (_pthread_sem_t * sem); - -int _pthread_sem_trywait (_pthread_sem_t * sem); - -int _pthread_sem_wait (_pthread_sem_t * sem); - -int _pthread_sem_timedwait (_pthread_sem_t * sem, +int _pthread_sem_timedwait (sem_t * sem,  			    const struct timespec * abstime); -int _pthread_sem_post (_pthread_sem_t * sem); -  #ifdef __cplusplus  }  #endif /* __cplusplus */ @@ -30,7 +30,9 @@  #endif /* !_MSC_VER && !__cplusplus && __GNUC__ */ +#include <sys/timeb.h>  #include "pthread.h" +#include "semaphore.h"  #include "implement.h" @@ -511,3 +513,102 @@ _pthread_callUserDestroyRoutines (pthread_t thread)  }				/* _pthread_callUserDestroyRoutines */ + +int +_pthread_sem_timedwait (sem_t * sem, const struct timespec * abstime) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function waits on a semaphore possibly until +      *      'abstime' time. +      * +      * PARAMETERS +      *      sem +      *              pointer to an instance of sem_t +      * +      *      abstime +      *              pointer to an instance of struct timespec +      * +      * 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. +      * +      *      If 'abstime' is a NULL pointer then this function will +      *      block until it can successfully decrease the value or +      *      until interrupted by a signal. +      * +      * RESULTS +      *              0               successfully decreased semaphore, +      *              -1              failed, error in errno +      * ERRNO +      *              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. +      *              ETIMEDOUT       abstime elapsed before success. +      * +      * ------------------------------------------------------ +      */ +{ +  int result = 0; + +#if defined(__MINGW32__) + +  struct timeb currSysTime; + +#else + +  struct _timeb currSysTime; + +#endif + +  const DWORD NANOSEC_PER_MILLISEC = 1000000; +  const DWORD MILLISEC_PER_SEC = 1000; +  DWORD milliseconds; + +  if (sem == NULL) +    { +      result = EINVAL; +    } +  else +    { +      if (abstime == NULL) +	{ +	  milliseconds = INFINITE; +	} +      else +	{ +	  /*  +	   * Calculate timeout as milliseconds from current system time.  +	   */ + +	  /* get current system time */ +	  _ftime(&currSysTime); + +	  /* subtract current system time from abstime */ +	  milliseconds = (abstime->tv_sec - currSysTime.time) * MILLISEC_PER_SEC; +	  milliseconds += (abstime->tv_nsec / NANOSEC_PER_MILLISEC) - +	    currSysTime.millitm; + +	  if (((int) milliseconds) < 0) +	    milliseconds = 0; +	} + +      result = (pthreadCancelableTimedWait (*sem, milliseconds)); +    } + +  if (result != 0) +    { + +      errno = result; +      return -1; + +    } + +  return 0; + +}				/* _pthread_sem_timedwait */ diff --git a/pthread.def b/pthread.def index f8630d0..1039497 100644 --- a/pthread.def +++ b/pthread.def @@ -1,5 +1,5 @@  ; pthread.def -; Last updated: $Date: 1999/02/09 17:55:00 $ +; Last updated: $Date: 1999/04/03 22:05:47 $  ; Currently unimplemented functions are commented out. @@ -73,6 +73,17 @@ pthread_setspecific  ;pthread_sigmask  pthread_testcancel  ; +; POSIX 1.b +; +sched_get_priority_min +sched_get_priority_max +sched_yield +sem_init +sem_destroy +sem_trywait +sem_wait +sem_post +;  ; Non-portable but useful  ;  pthread_mutexattr_setforcecs_np @@ -253,9 +253,6 @@ struct timespec {  #define FALSE	0  #endif /* !TRUE */ - -/* #include <sched.h> */ -  #ifdef __MINGW32__  #define PT_STDCALL  #else @@ -419,14 +416,14 @@ extern "C"  #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; +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;  /* @@ -501,141 +498,9 @@ struct pthread_once_t_  }; -/* - * ==================== - * ==================== - * 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; -#if HAVE_SIGSET_T -  sigset_t sigmask; -#endif /* HAVE_SIGSET_T */ -  int implicit:1; -  void *keys; -}; - +#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) -1) -/*  - * Special value to mark attribute objects as valid. - */ -#define _PTHREAD_ATTR_VALID ((unsigned long) 0xC4C0FFEE) - -struct pthread_attr_t_ { -  unsigned long valid; -  void *stackaddr; -  size_t stacksize; -  int detachstate; -  int priority; -#if HAVE_SIGSET_T -  sigset_t sigmask; -#endif /* HAVE_SIGSET_T */ -}; - - -/* - * ==================== - * ==================== - * Mutexes and Condition Variables - * ==================== - * ==================== - */ - -enum { -  _PTHREAD_OBJECT_INVALID = 0,  /* NULL */ -  _PTHREAD_OBJECT_AUTO_INIT -}; - -#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) _PTHREAD_OBJECT_AUTO_INIT) - -struct pthread_mutex_t_ { -  HANDLE mutex; -  CRITICAL_SECTION cs; -}; - - -struct pthread_mutexattr_t_ { -  int pshared; -  int forcecs; -}; - - -struct pthread_key_t_ { -  DWORD key; -  void (*destructor) (void *); -  pthread_mutex_t threadsLock; -  void *threads; -}; - - -#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) _PTHREAD_OBJECT_AUTO_INIT) - -typedef HANDLE _pthread_sem_t; - -struct pthread_cond_t_ { -  long waiters;                       /* # waiting threads             */ -  pthread_mutex_t waitersLock;        /* Mutex that guards access to  -					 waiter count                  */ -  _pthread_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; -}; +#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1)  /* @@ -655,13 +520,22 @@ struct pthread_condattr_t_ {  #define SCHED_MIN   SCHED_OTHER  #define SCHED_MAX   SCHED_RR -  struct sched_param { -    int sched_priority; -  }; - +struct sched_param { +  int sched_priority; +};  /* There are three implementations of cancel cleanup. + * Note that pthread.h is included in both application + * compilation units and also internally for the library. + * The code here and within the library aims to work + * for all reasonable combinations of environments. + * For example, although the library itself can't be + * built (yet) in C, an application written in C can + * be linked and run against a library built using + * either WIN32 SEH or C++ EH. + * + * The three implementations are:   *   *   WIN32 SEH   *   C @@ -963,17 +837,12 @@ int pthread_getschedparam (pthread_t thread,  			   int *policy,  			   struct sched_param *param); -int sched_get_priority_min (int policy); - -int sched_get_priority_max (int policy); -  int pthread_attr_getschedparam (const pthread_attr_t *attr,  				struct sched_param *param);  int pthread_attr_setschedparam (pthread_attr_t *attr,  				const struct sched_param *param); -  /*   * Protected Methods   * @@ -25,8 +25,7 @@  #define ENOSUP 0 -#include <errno.h> - +#include "sched.h"  #include "pthread.h"  #include "implement.h" @@ -150,3 +149,34 @@ int sched_get_priority_min(int policy)    /* This is independent of scheduling policy in Win32. */    return THREAD_PRIORITY_LOWEST;  } + +int sched_yield(void) +     /* +      * ------------------------------------------------------ +      * DOCPUBLIC +      *      This function indicates that the calling thread is +      *      willing to give up some time slices to other threads. +      * +      * PARAMETERS +      *      N/A +      * +      * +      * DESCRIPTION +      *      This function indicates that the calling thread is +      *      willing to give up some time slices to other threads. +      *      NOTE: Since this is part of POSIX 1003.1b +      *                (realtime extensions), it is defined as returning +      *                -1 if an error occurs and sets errno to the actual +      *                error. +      * +      * RESULTS +      *              0               successfully created semaphore, +      *              ENOSYS          sched_yield not supported, +      * +      * ------------------------------------------------------ +      */ +{ +  Sleep(0); + +  return 0; +} @@ -0,0 +1,73 @@ +/* + * Module: sched.h + * + * Purpose: + *      Provides an implementation of POSIX realtime extensions + *      as defined in  + * + *              POSIX 1003.1b-1993      (POSIX.1b) + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright (C) 1998 + * + * 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 + */ +#if !defined( SCHED_H ) +#define SCHED_H + +#ifdef _MSC_VER +/* + * 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 + +#include <windows.h> +#include <process.h> +#include <errno.h> + +#ifdef _MSC_VER +/* + * Re-enable all but 4127, 4514 + */ +#pragma warning( default : 4115 4116 4201 4214) +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif                          /* __cplusplus */ + +int sched_yield (void); + +int sched_get_priority_min (int policy); + +int sched_get_priority_max (int policy); + + +#ifdef __cplusplus +}                               /* End of extern "C" */ +#endif                          /* __cplusplus */ + + +#endif                          /* !SCHED_H */ diff --git a/semaphore.c b/semaphore.c index 0d46614..cd463d3 100644 --- a/semaphore.c +++ b/semaphore.c @@ -9,17 +9,6 @@   *   *              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   *              --------------                    ------ @@ -53,15 +42,17 @@   * MA 02111-1307, USA   */ +#include <windows.h> +#include <process.h>  #include <sys/timeb.h> -  #include <string.h> -#include <pthread.h> -#include "implement.h" +#include "pthread.h" +#include "semaphore.h" +  int -_pthread_sem_init (_pthread_sem_t * sem, int pshared, unsigned int value) +sem_init (sem_t * sem, int pshared, unsigned int value)       /*        * ------------------------------------------------------        * DOCPUBLIC @@ -70,7 +61,7 @@ _pthread_sem_init (_pthread_sem_t * sem, int pshared, unsigned int value)        *        * PARAMETERS        *      sem -      *              pointer to an instance of _pthread_sem_t +      *              pointer to an instance of sem_t        *        *      pshared        *              if zero, this semaphore may only be shared between @@ -87,6 +78,8 @@ _pthread_sem_init (_pthread_sem_t * sem, int pshared, unsigned int value)        *        * RESULTS        *              0               successfully created semaphore, +      *              -1              failed, error in errno +      * ERRNO        *              EINVAL          'sem' is not a valid semaphore,        *              ENOSPC          a required resource has been exhausted,        *              ENOSYS          semaphores are not supported, @@ -110,7 +103,7 @@ _pthread_sem_init (_pthread_sem_t * sem, int pshared, unsigned int value)      {        /*         * NOTE: Taking advantage of the fact that -       *               _pthread_sem_t is a simple structure with one entry; +       *               sem_t is a simple structure with one entry;         *               We don't have to allocate it...         */        *sem = CreateSemaphore ( @@ -125,13 +118,19 @@ _pthread_sem_init (_pthread_sem_t * sem, int pshared, unsigned int value)  	}      } -  return (result); +  if (result != 0) +    { +      errno = result; +      return -1; +    } + +  return 0;  }				/* sem_init */  int -_pthread_sem_destroy (_pthread_sem_t * sem) +sem_destroy (sem_t * sem)       /*        * ------------------------------------------------------        * DOCPUBLIC @@ -139,13 +138,15 @@ _pthread_sem_destroy (_pthread_sem_t * sem)        *        * PARAMETERS        *      sem -      *              pointer to an instance of _pthread_sem_t +      *              pointer to an instance of sem_t        *        * DESCRIPTION        *      This function destroys an unnamed semaphore.        *        * RESULTS        *              0               successfully destroyed semaphore, +      *              -1              failed, error in errno +      * ERRNO        *              EINVAL          'sem' is not a valid semaphore,        *              ENOSYS          semaphores are not supported,        *              EBUSY           threads (or processes) are currently @@ -154,17 +155,30 @@ _pthread_sem_destroy (_pthread_sem_t * sem)        * ------------------------------------------------------        */  { -  return ((sem == NULL) -	  ? EINVAL -	  : (CloseHandle (*sem) -	     ? 0 -	     : EINVAL)); +  int result = 0; + +  if (sem == NULL) +    { +      result = EINVAL; +    } +  else if (! CloseHandle (*sem)) +    { +      result = EINVAL; +    } + +  if (result != 0) +    { +      errno = result; +      return -1; +    } + +  return 0;  }				/* sem_destroy */  int -_pthread_sem_trywait (_pthread_sem_t * sem) +sem_trywait (sem_t * sem)       /*        * ------------------------------------------------------        * DOCPUBLIC @@ -172,7 +186,7 @@ _pthread_sem_trywait (_pthread_sem_t * sem)        *        * PARAMETERS        *      sem -      *              pointer to an instance of _pthread_sem_t +      *              pointer to an instance of sem_t        *        * DESCRIPTION        *      This function tries to wait on a semaphore. If the @@ -182,6 +196,8 @@ _pthread_sem_trywait (_pthread_sem_t * sem)        *        * RESULTS        *              0               successfully decreased semaphore, +      *              -1              failed, error in errno +      * ERRNO        *              EAGAIN          the semaphore was already locked,        *              EINVAL          'sem' is not a valid semaphore,        *              ENOSYS          semaphores are not supported, @@ -191,67 +207,38 @@ _pthread_sem_trywait (_pthread_sem_t * sem)        * ------------------------------------------------------        */  { -  return ((sem == NULL) -	  ? EINVAL -	  : ((WaitForSingleObject (*sem, 0) == WAIT_TIMEOUT) -	     ? EAGAIN -	     : 0)); - -}				/* sem_trywait */ +  int result = 0; +  if (sem == NULL) +    { +      result = EINVAL; +    } +  else if (WaitForSingleObject (*sem, 0) == WAIT_TIMEOUT) +    { +      result = EAGAIN; +    } -int -_pthread_sem_wait (_pthread_sem_t * sem) -     /* -      * ------------------------------------------------------ -      * DOCPUBLIC -      *      This function  waits on a semaphore. -      * -      * PARAMETERS -      *      sem -      *              pointer to an instance of _pthread_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 decreased 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. -      * -      * ------------------------------------------------------ -      */ -{ +  if (result != 0) +    { +      errno = result; +      return -1; +    } -  return ((sem == NULL) -	  ? EINVAL -	  : pthreadCancelableWait (*sem) -    ); +  return 0; -}				/* sem_wait */ +}				/* sem_trywait */  int -_pthread_sem_timedwait (_pthread_sem_t * sem, const struct timespec * abstime) +sem_wait (sem_t * sem)       /*        * ------------------------------------------------------        * DOCPUBLIC -      *      This function waits on a semaphore possibly until -      *      'abstime' time. +      *      This function  waits on a semaphore.        *        * PARAMETERS        *      sem -      *              pointer to an instance of _pthread_sem_t -      * -      *      abstime -      *              pointer to an instance of struct timespec +      *              pointer to an instance of sem_t        *        * DESCRIPTION        *      This function waits on a semaphore. If the @@ -261,64 +248,42 @@ _pthread_sem_timedwait (_pthread_sem_t * sem, const struct timespec * abstime)        *      successfully decrease the value or until interrupted by        *      a signal.        * -      *      If 'abstime' is a NULL pointer then this function will -      *      block until it can successfully decrease the value or -      *      until interrupted by a signal. -      *        * RESULTS        *              0               successfully decreased semaphore, +      *              -1              failed, error in errno +      * ERRNO        *              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. -      *              ETIMEDOUT       abstime elapsed before success.        *        * ------------------------------------------------------        */  { -#if defined(__MINGW32__) -  struct timeb currSysTime; -#else -  struct _timeb currSysTime; -#endif -  const DWORD NANOSEC_PER_MILLISEC = 1000000; -  const DWORD MILLISEC_PER_SEC = 1000; -  DWORD milliseconds; +  int result = 0;    if (sem == NULL)      { -      return EINVAL; -    } - -  if (abstime == NULL) -    { -      milliseconds = INFINITE; +      result = EINVAL;      }    else      { -      /*  -       * Calculate timeout as milliseconds from current system time.  -       */ - -      /* get current system time */ -      _ftime(&currSysTime); - -      /* subtract current system time from abstime */ -      milliseconds = (abstime->tv_sec - currSysTime.time) * MILLISEC_PER_SEC; -      milliseconds += (abstime->tv_nsec / NANOSEC_PER_MILLISEC) - -	currSysTime.millitm; +	result = pthreadCancelableWait (*sem); +    } -      if (((int) milliseconds) < 0) -	milliseconds = 0; +  if (result != 0) +    { +      errno = result; +      return -1;      } -  return (pthreadCancelableTimedWait (*sem, milliseconds)); +  return 0; -}				/* _pthread_sem_timedwait */ +}				/* sem_wait */  int -_pthread_sem_post (_pthread_sem_t * sem) +sem_post (sem_t * sem)       /*        * ------------------------------------------------------        * DOCPUBLIC @@ -326,7 +291,7 @@ _pthread_sem_post (_pthread_sem_t * sem)        *        * PARAMETERS        *      sem -      *              pointer to an instance of _pthread_sem_t +      *              pointer to an instance of sem_t        *        * DESCRIPTION        *      This function posts a wakeup to a semaphore. If there @@ -334,17 +299,33 @@ _pthread_sem_post (_pthread_sem_t * sem)        *      otherwise, the semaphore value is incremented by one.        *        * RESULTS -      *              0               successfully destroyed semaphore, +      *              0               successfully posted semaphore, +      *              -1              failed, error in errno +      * ERRNO        *              EINVAL          'sem' is not a valid semaphore,        *              ENOSYS          semaphores are not supported,        *        * ------------------------------------------------------        */  { -  return ((sem == NULL) -	  ? EINVAL -	  : (ReleaseSemaphore (*sem, 1, 0) -	     ? 0 -	     : EINVAL)); +  int result = 0; + +  if (sem == NULL) +    { +	result = EINVAL; +    } +  else if (! ReleaseSemaphore (*sem, 1, 0)) +    { +	result = EINVAL; +    } + + +  if (result != 0) +    { +      errno = result; +      return -1; +    } + +  return 0;  }				/* sem_post */ diff --git a/semaphore.h b/semaphore.h new file mode 100644 index 0000000..f5d9c83 --- /dev/null +++ b/semaphore.h @@ -0,0 +1,62 @@ +/* + * 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) + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright (C) 1998 + * + * 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 + */ +#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 */ diff --git a/tests/ChangeLog b/tests/ChangeLog index 7354fba..e0969ef 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,12 @@ +Sun Apr  4 12:04:28 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au> + +	* tsd1.c (mythread): Change Sleep(0) to sched_yield(). +	(sched.h): Include. + +	* condvar3.c (mythread): Remove redundant Sleep(). + +	* runtest.bat: Re-organised to make more informative. +  Fri Mar 19 1999  Ross Johnson  <rpj@ixobrychus.canberra.edu.au>  	* *.bat: redirect unwanted output to nul: diff --git a/tests/condvar3.c b/tests/condvar3.c index c2b08e6..ab1080e 100644 --- a/tests/condvar3.c +++ b/tests/condvar3.c @@ -59,8 +59,6 @@ enum {  void *  mythread(void * arg)  { -  Sleep(1); -    assert(pthread_mutex_lock(&mutex) == 0);    shared++; diff --git a/tests/runall.bat b/tests/runall.bat index 21bbbbe..3f5498d 100644 --- a/tests/runall.bat +++ b/tests/runall.bat @@ -1,4 +1,6 @@ -erase *.result +@echo off + +if x%1==x-f echo y | erase *.pass > nul:  call runtest cl mutex1  call runtest cl mutex2 diff --git a/tests/runtest.bat b/tests/runtest.bat index 03a9413..4a06505 100644 --- a/tests/runtest.bat +++ b/tests/runtest.bat @@ -2,38 +2,47 @@  REM Usage: runtest cl|gcc testname testarg ... -echo y | erase /s tmp > nul: +if EXIST %2.pass goto bypass + +REM Make sure we start with only those files we expect to need +if exist tmp\*.* echo y | erase tmp\*.* > nul:  rmdir tmp  mkdir tmp -cd tmp -REM Make sure we start with only those files we expect to need -if exist pthread.dll erase pthread.dll > nul: -if exist pthread.h erase pthread.h > nul: -if exist test.h erase test.h > nul: -if exist pthread.lib erase pthread.lib > nul: -if exist libpthread32.a erase libpthread32.a > nul: -copy ..\..\pthread.dll . > nul: -copy ..\..\pthread.h . > nul: -copy ..\test.h . > nul: -copy ..\..\pthread.lib . > nul: -copy ..\..\libpthread32.a . > nul: +copy ..\pthread.dll tmp > nul: +copy ..\pthread.h tmp > nul: +copy ..\semaphore.h tmp > nul: +copy ..\sched.h tmp > nul: +copy test.h tmp > nul: +copy ..\pthread.lib tmp > nul: +copy ..\libpthread32.a tmp > nul: + +cd tmp  REM Compile the test case  REM  produces aout.exe using the compiler given as %1 -call ..\c%1.bat %2 > nul: +call ..\c%1.bat %2 > ..\%2.%1log + +if ERRORLEVEL 1 goto cleanup + +REM erase ..\%2.%1log -echo TEST: %2 [%1] > ..\%2.result +echo TEST: %2 [%1]  REM Run the test case -aout.exe %3 %4 %5 %6 %7 %8 %9 >> ..\%2.result +aout.exe %3 %4 %5 %6 %7 %8 %9 + +set RESULT=%ERRORLEVEL% + +if %RESULT% EQU 0 echo Passed [%RESULT%] > ..\%2.pass + +:cleanup -REM Clean up -erase aout.exe > nul: -if exist pthread.dll erase pthread.dll > nul: -if exist pthread.h erase pthread.h > nul: -if exist pthread.lib erase pthread.lib > nul: -if exist libpthread32.a erase libpthread32.a > nul:  cd .. -more < %2.result +REM Clean up +if exist tmp\*.* echo y | erase tmp\*.* > nul: + +if EXIST %2.pass echo Passed [%RESULT%] + +:bypass
\ No newline at end of file diff --git a/tests/tsd1.c b/tests/tsd1.c index 9448c10..9926a30 100644 --- a/tests/tsd1.c +++ b/tests/tsd1.c @@ -43,6 +43,7 @@   * - output identifies failed component   */ +#include <sched.h>  #include "test.h"  static pthread_key_t key = NULL; @@ -87,7 +88,7 @@ mythread(void * arg)  {    while (key == NULL)      { -	Sleep(0); +	sched_yield();      }    setkey(arg); | 
