From 451bb0670ddd5f5c0606410f2b5f51733119645d Mon Sep 17 00:00:00 2001 From: rpj Date: Sat, 3 Apr 1999 22:05:39 +0000 Subject: ./ChangeLog Sun Apr 4 11:05:57 1999 Ross Johnson * 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 * Makefile.in (OBJS): Add errno.o. Fri Apr 2 11:08:50 1999 Ross Johnson * 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 (_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. tests/ChangeLog Sun Apr 4 12:04:28 1999 Ross Johnson * 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. --- ANNOUNCE | 62 +++++++++++----- ChangeLog | 44 +++++++++++ Makefile.in | 4 +- condvar.c | 17 +++-- create.c | 6 -- errno.c | 87 ++++++++++++++++++++++ implement.h | 137 ++++++++++++++++++++++++++++++---- private.c | 101 +++++++++++++++++++++++++ pthread.def | 13 +++- pthread.h | 177 ++++++-------------------------------------- sched.c | 34 ++++++++- sched.h | 73 ++++++++++++++++++ semaphore.c | 215 +++++++++++++++++++++++++----------------------------- semaphore.h | 62 ++++++++++++++++ tests/ChangeLog | 9 +++ tests/condvar3.c | 2 - tests/runall.bat | 4 +- tests/runtest.bat | 55 ++++++++------ tests/tsd1.c | 3 +- 19 files changed, 756 insertions(+), 349 deletions(-) create mode 100644 errno.c create mode 100644 sched.h create mode 100644 semaphore.h diff --git a/ANNOUNCE b/ANNOUNCE index 00987c4..f481f7c 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -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 -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 . @@ -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 @@ -111,6 +123,15 @@ The following functions are implemented: pthread_cond_signal 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 --------------------------- @@ -118,9 +139,10 @@ The following functions are implemented: 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: diff --git a/ChangeLog b/ChangeLog index b51027b..f36a26a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,47 @@ +Sun Apr 4 11:05:57 1999 Ross Johnson + + * 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 + + * Makefile.in (OBJS): Add errno.o. + +Fri Apr 2 11:08:50 1999 Ross Johnson + + * 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 + (_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 * 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 diff --git a/condvar.c b/condvar.c index 2643413..714d642 100644 --- a/condvar.c +++ b/condvar.c @@ -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) diff --git a/create.c b/create.c index 8d258f0..e085179 100644 --- a/create.c +++ b/create.c @@ -27,10 +27,6 @@ #include "pthread.h" #include "implement.h" -/* - * Code contributed by John E. Bossom . - */ - int pthread_create (pthread_t * tid, const pthread_attr_t * attr, @@ -168,5 +164,3 @@ FAIL0: } /* pthread_create */ -/* */ - diff --git a/errno.c b/errno.c new file mode 100644 index 0000000..e6cf5e7 --- /dev/null +++ b/errno.c @@ -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 + +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 */ diff --git a/private.c b/private.c index dd6890c..9a69768 100644 --- a/private.c +++ b/private.c @@ -30,7 +30,9 @@ #endif /* !_MSC_VER && !__cplusplus && __GNUC__ */ +#include #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 diff --git a/pthread.h b/pthread.h index bc11d1b..8995558 100644 --- a/pthread.h +++ b/pthread.h @@ -253,9 +253,6 @@ struct timespec { #define FALSE 0 #endif /* !TRUE */ - -/* #include */ - #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 * diff --git a/sched.c b/sched.c index c07698b..6d53d9b 100644 --- a/sched.c +++ b/sched.c @@ -25,8 +25,7 @@ #define ENOSUP 0 -#include - +#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; +} diff --git a/sched.h b/sched.h new file mode 100644 index 0000000..77e91ad --- /dev/null +++ b/sched.h @@ -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 +#include +#include + +#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 +#include #include - #include -#include -#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 +#include + +#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 + + * 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 * *.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 #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); -- cgit v1.2.3