summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ANNOUNCE62
-rw-r--r--ChangeLog44
-rw-r--r--Makefile.in4
-rw-r--r--condvar.c17
-rw-r--r--create.c6
-rw-r--r--errno.c87
-rw-r--r--implement.h137
-rw-r--r--private.c101
-rw-r--r--pthread.def13
-rw-r--r--pthread.h177
-rw-r--r--sched.c34
-rw-r--r--sched.h73
-rw-r--r--semaphore.c215
-rw-r--r--semaphore.h62
-rw-r--r--tests/ChangeLog9
-rw-r--r--tests/condvar3.c2
-rw-r--r--tests/runall.bat4
-rw-r--r--tests/runtest.bat55
-rw-r--r--tests/tsd1.c3
19 files changed, 756 insertions, 349 deletions
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 <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:
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 <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
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 <JEB>.
- */
-
int
pthread_create (pthread_t * tid,
const pthread_attr_t * attr,
@@ -168,5 +164,3 @@ FAIL0:
} /* pthread_create */
-/* </JEB> */
-
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 <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 */
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 <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
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 <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
*
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 <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;
+}
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 <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);