summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ANNOUNCE71
-rw-r--r--ChangeLog12
-rw-r--r--Nmakefile.tests290
-rw-r--r--condvar.c121
-rw-r--r--pthread.def7
-rw-r--r--pthread.h15
-rw-r--r--sched.c239
-rw-r--r--sched.h31
-rw-r--r--semaphore.c73
-rw-r--r--semaphore.h30
10 files changed, 378 insertions, 511 deletions
diff --git a/ANNOUNCE b/ANNOUNCE
index 689b16d..573d15c 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -23,10 +23,8 @@ Please see the 'Acknowledgements' section at the end of this
announcement for the list of contributors.
-Change Summary (since the last snapshot)
-----------------------------------------
-
-(See the ChangeLog file for details.)
+Changes since the last snapshot
+-------------------------------
-----------------------
Additions to Scheduling
@@ -113,11 +111,13 @@ values.
------------------
Changes to Mutexes
------------------
+Background:
Snapshot-2001-06-06 included Thomas Pfaff's enhancements
to the mutex routines to improve speed. The improvements
-are most apparent on Win9x class systems where pthreads-win32
+are very large on Win9x class systems where pthreads-win32
previously used Win32 mutexes rather than critical
-sections as the underlying mechanism. The enhancements
+sections as the underlying mechanism. On WNT systems speed
+appears to have decreased a little. On Win9x the enhancements
also resulted in speed improvements in other primitives
which use mutexes internally, such as condition variables
and read-write locks. Thomas also added mutex
@@ -126,6 +126,11 @@ Specification documentation, and as provided with
the majority of major Unix and Linux Pthreads
implementations.
+Overall, the library provides far more consistent performance
+across the different Windows variants with greater compatibility.
+Future work will continue to improve on this.
+
+New changes:
Changes have been made to further improve the speed of the
default PTHREAD_MUTEX_NORMAL type (and therefore also
PTHREAD_MUTEX_DEFAULT which is equivalent in pthreads-win32).
@@ -160,14 +165,62 @@ These mutex changes appear to be consistent with both
the behaviour exhibited by other implementations and their
documentation, including the Open Group documentation.
+------------
+Benchmarking
+------------
+There is a new but growing set a benchmarking programs in the
+"tests" directory. These should be runnable using the
+following command-lines corresponding to each of the possible
+library builds:
--------
-Bug fix
--------
+MSVC:
+nmake clean VC-bench
+nmake clean VCE-bench
+nmake clean VSE-bench
+
+Mingw32:
+make clean GC-bench
+make clean GCE-bench
+
+UWIN:
+The benchtests are run as part of the testsuite.
+
+Currently these only provide timing for various
+synchronisation senarios for the different mutex types.
+Each test does timings for each of the implemented
+mutex types and, for reference, also repeats the same
+tests using the following:
+
+Simple Critical Section
+POSIX mutex implemented using a Critical Section
+POSIX mutex implemented using a Win32 Mutex
+
+The later two represent the old implementation under
+WNT and W9x respectively.
+
+The mutex types tested are:
+PTHREAD_MUTEX_DEFAULT
+PTHREAD_MUTEX_NORMAL
+PTHREAD_MUTEX_ERRORCHECK
+PTHREAD_MUTEX_RECURSIVE
+
+These tests indicate that is may be worthwhile re-introducing
+runtime adaptation of the underlying Win32 synchronisation
+mechanism for WinNT.
+
+
+---------
+Bug fixes
+---------
Pthread_create now sets the priority of the new thread
from the value set in the thread attribute.
- from Ralf.Brese@pdb4.siemens.de.
+A "lost signal" bug in condition variables that I introduced
+in the last snapshot has been fixed.
+- fixed by Alexander Terekhov
+- reported by Timur Aydin taydin@snet.net
+
---------------------------
Known bugs in this snapshot
diff --git a/ChangeLog b/ChangeLog
index 70b1755..d43e0e8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2001-07-01 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ Contributed by - Alexander Terekhov.
+
+ * condvar.c: Fixed lost signal bug reported by Timur Aydin
+ (taydin@snet.net).
+ [RPJ (me) didn't translate the original algorithm
+ correctly.]
+ * semaphore.c: Added sem_post_multiple; this is a useful
+ routine, but it doesn't appear to be standard. For now it's
+ not an exported function.
+
2001-06-25 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
* create.c (pthread_create): Add priority inheritance
diff --git a/Nmakefile.tests b/Nmakefile.tests
index 4829938..8e124ab 100644
--- a/Nmakefile.tests
+++ b/Nmakefile.tests
@@ -1,141 +1,149 @@
-/* for running tests */
-CCFLAGS = -g
-_MT == 1
-_timeb == timeb
-_ftime == ftime
-
-.SOURCE: tests
-/*
-:PACKAGE: pthread
-*/
-
-set keepgoing
-
-":test:" : .MAKE .OPERATOR
- local I
- $(<:D:B:S=.pass) : .IMPLICIT $(>:D:B:S=.pass)
- for I $(<) $(>)
- $(I:D:B:S=.pass) : .VIRTUAL .FORCE $(I)
- $(>)
- end
-loadfree:: loadfree.c
-mutex1:: mutex1.c
-mutex1e:: mutex1e.c
-mutex1n:: mutex1n.c
-mutex1r:: mutex1r.c
-mutex2:: mutex1.2
-exit1:: exit1.c
-condvar1:: condvar1.c
-self1:: self1.c
-condvar2:: condvar2.c
-condvar2_1:: condvar2_1.c
-condvar3_1:: condvar3_1.c
-condvar3_2:: condvar3_2.c
-create1.:: create1.c
-cancel1:: cancel1.c
-cancel2:: cancel2.c
-mutex3:: mutex3.c
-mutex4:: mutex4.c
-mutex5:: mutex5.c
-mutex6:: mutex6.c
-mutex6e:: mutex6e.c
-mutex6n:: mutex6n.c
-mutex6r:: mutex6r.c
-equal1:: equal1.c
-exit2:: exit2.c
-exit3:: exit3.c
-join0:: join0.c
-join1:: join1.c
-join2:: join2.c
-count1:: count1.c
-once1:: once1.c
-tsd1:: tsd1.c
-self2:: self2.c
-eyal1:: eyal1.c
-condvar3:: condvar3.c
-condvar4:: condvar4.c
-condvar5:: condvar5.c
-condvar6:: condvar6.c
-condvar7:: condvar7.c
-condvar8:: condvar8.c
-condvar9:: condvar9.c
-errno1:: errno1.c
-rwlock1:: rwlock1.c
-rwlock2:: rwlock2.c
-rwlock3:: rwlock3.c
-rwlock4:: rwlock4.c
-rwlock5:: rwlock5.c
-rwlock6:: rwlock6.c
-rwlock7:: rwlock7.c
-context1:: context1.c
-cancel3:: cancel3.c
-cancel4:: cancel4.c
-cancel5:: cancel5.c
-cleanup0:: cleanup0.c
-cleanup1:: cleanup1.c
-cleanup2:: cleanup2.c
-cleanup3:: cleanup3.c
-exception1:: exception1.c
-exception2:: exception2.c
-exception3:: exception3.c
-priority1:: priority1.c
-priority2:: priority2.c
-inherit1:: inherit1.c
-benchtest1:: benchtest1.c
-benchtest2:: benchtest2.c
-
-loadfree: :test:
-mutex5 :test: loadfree
-mutex1 :test: loadfree
-mutex2 :test: loadfree
-exit1 :test: loadfree
-condvar1 :test: loadfree
-self1 :test: loadfree
-condvar2 :test: condvar1
-create1 :test: mutex2
-cancel1 :test: create1
-cancel2 :test: cancel1
-mutex3 :test: create1
-mutex4 :test: mutex3
-equal1 :test: create1
-exit2 :test: create1
-exit3 :test: create1
-join0 :test: create1
-join1 :test: create1
-join2 :test: create1
-count1 :test: join1
-once1 :test: create1
-tsd1 :test: join1
-self2 :test: create1
-eyal1 :test: tsd1
-condvar3 :test: create1
-condvar4 :test: create1
-condvar5 :test: condvar4
-condvar6 :test: condvar5
-condvar7 :test: condvar6 cleanup1
-condvar8 :test: condvar7
-condvar9 :test: condvar8
-errno1 :test: mutex3
-rwlock1 :test: condvar6
-rwlock2 :test: rwlock1
-rwlock3 :test: rwlock2
-rwlock4 :test: rwlock3
-rwlock5 :test: rwlock4
-rwlock6 :test: rwlock5
-context1 :test: cancel2
-cancel3 :test: context1
-cancel4 :test: cancel3
-cancel5 :test: cancel3
-cleanup0 :test: cancel5
-cleanup1 :test: cleanup0
-cleanup2 :test: cleanup1
-cleanup3 :test: cleanup2
-priority1 :test: join1
-priority2 :test: priority1
-inherit1 :test: join1
-exception1 :test: cancel4
-exception2 :test: exception1
-benchtest1 :test: mutex3
-benchtest2 :test: benchtest1
-exception3 :test: exception2
-
+/* for running tests */
+CCFLAGS = -g
+_MT == 1
+_timeb == timeb
+_ftime == ftime
+
+.SOURCE: tests
+/*
+:PACKAGE: pthread
+*/
+
+set keepgoing
+
+":test:" : .MAKE .OPERATOR
+ local I
+ $(<:D:B:S=.pass) : .IMPLICIT $(>:D:B:S=.pass)
+ for I $(<) $(>)
+ $(I:D:B:S=.pass) : .VIRTUAL .FORCE $(I)
+ $(>)
+ end
+loadfree:: loadfree.c
+mutex1:: mutex1.c
+mutex1e:: mutex1e.c
+mutex1n:: mutex1n.c
+mutex1r:: mutex1r.c
+mutex2:: mutex1.2
+exit1:: exit1.c
+condvar1:: condvar1.c
+self1:: self1.c
+condvar2:: condvar2.c
+condvar2_1:: condvar2_1.c
+condvar3_1:: condvar3_1.c
+condvar3_2:: condvar3_2.c
+condvar3_3:: condvar3_3.c
+create1.:: create1.c
+cancel1:: cancel1.c
+cancel2:: cancel2.c
+mutex3:: mutex3.c
+mutex4:: mutex4.c
+mutex5:: mutex5.c
+mutex6:: mutex6.c
+mutex6e:: mutex6e.c
+mutex6n:: mutex6n.c
+mutex6r:: mutex6r.c
+equal1:: equal1.c
+exit2:: exit2.c
+exit3:: exit3.c
+join0:: join0.c
+join1:: join1.c
+join2:: join2.c
+count1:: count1.c
+once1:: once1.c
+tsd1:: tsd1.c
+self2:: self2.c
+eyal1:: eyal1.c
+condvar3:: condvar3.c
+condvar4:: condvar4.c
+condvar5:: condvar5.c
+condvar6:: condvar6.c
+condvar7:: condvar7.c
+condvar8:: condvar8.c
+condvar9:: condvar9.c
+errno1:: errno1.c
+rwlock1:: rwlock1.c
+rwlock2:: rwlock2.c
+rwlock3:: rwlock3.c
+rwlock4:: rwlock4.c
+rwlock5:: rwlock5.c
+rwlock6:: rwlock6.c
+rwlock7:: rwlock7.c
+context1:: context1.c
+cancel3:: cancel3.c
+cancel4:: cancel4.c
+cancel5:: cancel5.c
+cleanup0:: cleanup0.c
+cleanup1:: cleanup1.c
+cleanup2:: cleanup2.c
+cleanup3:: cleanup3.c
+priority1:: priority1.c
+priority2:: priority2.c
+inherit1:: inherit1.c
+exception1:: exception1.c
+exception2:: exception2.c
+exception3:: exception3.c
+benchtest1:: benchtest1.c
+benchtest2:: benchtest2.c
+benchtest3:: benchtest3.c
+benchtest4:: benchtest4.c
+
+loadfree: :test:
+mutex1 :test: loadfree
+mutex2 :test: loadfree
+exit1 :test: loadfree
+condvar1 :test: loadfree
+self1 :test: loadfree
+condvar2 :test: condvar1
+condvar2_1 :test: condvar2
+create1 :test: mutex2
+cancel1 :test: create1
+cancel2 :test: cancel1
+mutex3 :test: create1
+mutex4 :test: mutex3
+equal1 :test: create1
+exit2 :test: create1
+exit3 :test: create1
+join0 :test: create1
+join1 :test: create1
+join2 :test: create1
+count1 :test: join1
+once1 :test: create1
+tsd1 :test: join1
+self2 :test: create1
+eyal1 :test: tsd1
+condvar3 :test: create1
+condvar3_1 :test: condvar3
+condvar3_2 :test: condvar3_1
+condvar3_3 :test: condvar3_2
+condvar4 :test: create1
+condvar5 :test: condvar4
+condvar6 :test: condvar5
+condvar7 :test: condvar6 cleanup1
+condvar8 :test: condvar7
+condvar9 :test: condvar8
+errno1 :test: mutex3
+rwlock1 :test: condvar6
+rwlock2 :test: rwlock1
+rwlock3 :test: rwlock2
+rwlock4 :test: rwlock3
+rwlock5 :test: rwlock4
+rwlock6 :test: rwlock5
+context1 :test: cancel2
+cancel3 :test: context1
+cancel4 :test: cancel3
+cancel5 :test: cancel3
+cleanup0 :test: cancel5
+cleanup1 :test: cleanup0
+cleanup2 :test: cleanup1
+cleanup3 :test: cleanup2
+priority1 :test: join1
+priority2 :test: priority1
+inherit1 :test: join1
+benchtest1 :test: mutex3
+benchtest2 :test: benchtest1
+benchtest3 :test: benchtest2
+benchtest4 :test: benchtest3
+exception1 :test: cancel4
+exception2 :test: exception1
+exception3 :test: exception2
+
diff --git a/condvar.c b/condvar.c
index 3607594..65d4e5f 100644
--- a/condvar.c
+++ b/condvar.c
@@ -693,7 +693,7 @@ ptw32_cond_wait_cleanup(void * args)
pthread_cond_t cv = cleanup_args->cv;
int * resultPtr = cleanup_args->resultPtr;
int nSignalsWasLeft;
- int nWaitersWasGone = 0;
+ int nWaitersWasGone = 0; /* Initialised to quell warnings. */
int result;
/*
@@ -701,17 +701,16 @@ ptw32_cond_wait_cleanup(void * args)
* timeout on wait or thread cancellation we indicate that we are no
* longer waiting. The waiter is responsible for adjusting waiters
* (to)unblock(ed) counts (protected by unblock lock).
- * Unblock lock/Sync.LEVEL-2 supports _timedwait and cancellation.
*/
if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
{
*resultPtr = result;
- goto FAIL0;
+ return;
}
if ( 0 != (nSignalsWasLeft = cv->nWaitersToUnblock) )
{
- if ( ! cleanup_args->signaled )
+ if ( !cleanup_args->signaled )
{
if ( 0 != cv->nWaitersBlocked )
{
@@ -729,7 +728,8 @@ ptw32_cond_wait_cleanup(void * args)
if (sem_post( &(cv->semBlockLock) ) != 0)
{
*resultPtr = errno;
- goto FAIL1;
+ (void) pthread_mutex_unlock( &(cv->mtxUnblockLock) );
+ return;
}
nSignalsWasLeft = 0;
}
@@ -744,64 +744,46 @@ ptw32_cond_wait_cleanup(void * args)
if (sem_wait( &(cv->semBlockLock) ) != 0)
{
*resultPtr = errno;
- goto FAIL1;
+ (void) pthread_mutex_unlock( &(cv->mtxUnblockLock) );
+ return;
}
cv->nWaitersBlocked -= cv->nWaitersGone;
if (sem_post( &(cv->semBlockLock) ) != 0)
{
*resultPtr = errno;
- goto FAIL1;
+ (void) pthread_mutex_unlock( &(cv->mtxUnblockLock) );
+ return;
}
cv->nWaitersGone = 0;
}
- /*
- * No more LEVEL-2 access to waiters (to)unblock(ed) counts needed
- */
if ((result = pthread_mutex_unlock(&(cv->mtxUnblockLock))) != 0)
{
*resultPtr = result;
- goto FAIL0;
+ return;
}
- /*
- * If last signal...
- */
if ( 1 == nSignalsWasLeft )
{
if ( 0 != nWaitersWasGone )
{
// sem_adjust( &(cv->semBlockQueue), -nWaitersWasGone );
- while ( nWaitersWasGone-- ) {
- if (sem_wait( &(cv->semBlockQueue)) != 0 )
- {
- *resultPtr = errno;
- goto FAIL0;
- }
- }
+ while ( nWaitersWasGone-- )
+ {
+ if (sem_wait( &(cv->semBlockQueue)) != 0 )
+ {
+ *resultPtr = errno;
+ return;
+ }
+ }
}
- /*
- * ...it means that we have end of 'atomic' signal/broadcast
- */
if (sem_post(&(cv->semBlockLock)) != 0)
{
*resultPtr = errno;
- goto FAIL0;
+ return;
}
}
- goto DONE;
-
- FAIL1:
- if ((result = pthread_mutex_unlock(&(cv->mtxUnblockLock))) != 0)
- {
- *resultPtr = result;
- }
-
- FAIL0:
- return;
-
- DONE:
/*
* XSH: Upon successful return, the mutex has been locked and is owned
* by the calling thread
@@ -845,9 +827,6 @@ ptw32_cond_timedwait (pthread_cond_t * cond,
cv = *cond;
- /*
- * Synchronize access to waiters blocked count (LEVEL-1)
- */
if (sem_wait(&(cv->semBlockLock)) != 0)
{
return errno;
@@ -855,9 +834,6 @@ ptw32_cond_timedwait (pthread_cond_t * cond,
cv->nWaitersBlocked++;
- /*
- * Thats it. Counted means waiting, no more access needed
- */
if (sem_post(&(cv->semBlockLock)) != 0)
{
return errno;
@@ -948,9 +924,8 @@ ptw32_cond_unblock (pthread_cond_t * cond,
*/
{
int result;
- int result2;
pthread_cond_t cv;
- int nSignalsToIssue = 1;
+ int nSignalsToIssue;
if (cond == NULL || *cond == NULL)
{
@@ -968,10 +943,6 @@ ptw32_cond_unblock (pthread_cond_t * cond,
return 0;
}
- /*
- * Synchronize access to waiters (to)unblock(ed) counts (LEVEL-2)
- * This sync.level supports _timedwait and cancellation
- */
if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
{
return result;
@@ -981,7 +952,7 @@ ptw32_cond_unblock (pthread_cond_t * cond,
{
if ( 0 == cv->nWaitersBlocked )
{
- goto FAIL1;
+ return pthread_mutex_unlock( &(cv->mtxUnblockLock) );
}
if (unblockAll)
{
@@ -990,60 +961,48 @@ ptw32_cond_unblock (pthread_cond_t * cond,
}
else
{
+ nSignalsToIssue = 1;
cv->nWaitersToUnblock++;
cv->nWaitersBlocked--;
}
}
- else
+ else if ( cv->nWaitersBlocked > cv->nWaitersGone )
{
if (sem_wait( &(cv->semBlockLock) ) != 0)
{
result = errno;
- goto FAIL1;
+ (void) pthread_mutex_unlock( &(cv->mtxUnblockLock) );
+ return result;
}
- if ( cv->nWaitersBlocked > cv->nWaitersGone )
+ if ( 0 != cv->nWaitersGone )
{
- if ( 0 != cv->nWaitersGone )
- {
- cv->nWaitersBlocked -= cv->nWaitersGone;
- cv->nWaitersGone = 0;
- }
- if (unblockAll)
- {
- nSignalsToIssue = cv->nWaitersToUnblock = cv->nWaitersBlocked;
- cv->nWaitersBlocked = 0;
- }
- else
- {
- nSignalsToIssue = cv->nWaitersToUnblock = 1;
- cv->nWaitersBlocked--;
- }
+ cv->nWaitersBlocked -= cv->nWaitersGone;
+ cv->nWaitersGone = 0;
+ }
+ if (unblockAll)
+ {
+ nSignalsToIssue = cv->nWaitersToUnblock = cv->nWaitersBlocked;
+ cv->nWaitersBlocked = 0;
}
else
{
- if (sem_post( &(cv->semBlockLock) ) != 0)
- {
- result = errno;
- goto FAIL1;
- }
+ nSignalsToIssue = cv->nWaitersToUnblock = 1;
+ cv->nWaitersBlocked--;
}
}
-
- FAIL1:
- if ((result2 = pthread_mutex_unlock( &(cv->mtxUnblockLock) )) != 0)
+ else
{
- result = result2;
+ return pthread_mutex_unlock( &(cv->mtxUnblockLock) );
}
- while (0 != nSignalsToIssue--)
+
+ if ((result = pthread_mutex_unlock( &(cv->mtxUnblockLock) )) == 0)
{
- if (sem_post( &(cv->semBlockQueue) ) != 0)
+ if (sem_post_multiple( &(cv->semBlockQueue), nSignalsToIssue ) != 0)
{
result = errno;
- goto FAIL0;
}
}
- FAIL0:
return result;
} /* ptw32_cond_unblock */
diff --git a/pthread.def b/pthread.def
index 2915077..9ca0cbd 100644
--- a/pthread.def
+++ b/pthread.def
@@ -1,5 +1,5 @@
; pthread.def
-; Last updated: $Date: 2001/07/01 13:23:10 $
+; Last updated: $Date: 2001/07/01 14:35:50 $
; Currently unimplemented functions are commented out.
@@ -82,7 +82,6 @@ pthread_testcancel
;
sched_get_priority_min
sched_get_priority_max
-sched_rr_set_interval
sched_getscheduler
sched_setscheduler
sched_yield
@@ -96,6 +95,10 @@ sem_close
sem_unlink
sem_getvalue
;
+; This next one is a macro
+;sched_rr_get_interval
+;
+;
; Read/Write Locks
;
pthread_rwlock_init
diff --git a/pthread.h b/pthread.h
index a860cd1..8675c56 100644
--- a/pthread.h
+++ b/pthread.h
@@ -22,9 +22,6 @@
#if !defined( PTHREAD_H )
#define PTHREAD_H
-#if !defined( PTW32_HEADER )
-#define PTW32_HEADER
-
#ifdef _UWIN
# define HAVE_STRUCT_TIMESPEC 1
# define HAVE_SIGNAL_H 1
@@ -32,8 +29,6 @@
# pragma comment(lib, "pthread")
#endif
-#endif /* PTW32_HEADER */
-
/*
* -------------------------------------------------------------
*
@@ -125,8 +120,7 @@
#include <setjmp.h>
-#if ! defined(HAVE_STRUCT_TIMESPEC) && ! defined(PTW32_TIMESPEC)
-#define PTW32_TIMESPEC
+#ifndef HAVE_STRUCT_TIMESPEC
struct timespec {
long tv_sec;
long tv_nsec;
@@ -162,7 +156,7 @@ struct timespec {
* In case ETIMEDOUT hasn't been defined above somehow.
*/
#ifndef ETIMEDOUT
-#define ETIMEDOUT 10060 /* This is the value in winsock.h. */
+# define ETIMEDOUT 10060 /* This is the value in winsock.h. */
#endif
/*
@@ -173,7 +167,6 @@ struct timespec {
# define ENOTSUP 48
#endif
-
#ifdef __cplusplus
extern "C"
{
@@ -657,7 +650,7 @@ int pthread_attr_setstacksize (pthread_attr_t * attr,
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);
@@ -675,7 +668,7 @@ int pthread_attr_getinheritsched(pthread_attr_t * attr,
int pthread_attr_setscope (pthread_attr_t *,
int);
-
+
int pthread_attr_getscope (const pthread_attr_t *,
int *);
diff --git a/sched.c b/sched.c
index 6f558ab..bc8aca0 100644
--- a/sched.c
+++ b/sched.c
@@ -91,11 +91,7 @@ pthread_attr_setschedparam(pthread_attr_t *attr,
priority = param->sched_priority;
- /*
- * Validate priority level. Don't check the
- * return values of the function calls because
- * we're sure they will succeed.
- */
+ /* Validate priority level. */
if (priority < sched_get_priority_min(SCHED_OTHER) ||
priority > sched_get_priority_max(SCHED_OTHER))
{
@@ -109,7 +105,7 @@ pthread_attr_setschedparam(pthread_attr_t *attr,
int
pthread_attr_getschedparam(const pthread_attr_t *attr,
- struct sched_param *param)
+ struct sched_param *param)
{
if (is_attr(attr) != 0 || param == NULL)
{
@@ -177,13 +173,9 @@ pthread_setschedparam(pthread_t thread, int policy,
return ENOTSUP;
}
- /*
- * Validate priority level. Don't check the
- * return values of the function calls because
- * we're sure they will succeed.
- */
- if (param->sched_priority < sched_get_priority_min(SCHED_OTHER) ||
- param->sched_priority > sched_get_priority_max(SCHED_OTHER))
+ /* Validate priority level. */
+ if (param->sched_priority < sched_get_priority_min(policy) ||
+ param->sched_priority > sched_get_priority_max(policy))
{
return EINVAL;
}
@@ -253,14 +245,7 @@ sched_get_priority_max(int policy)
{
if (policy < SCHED_MIN || policy > SCHED_MAX)
{
- errno = EINVAL;
- return -1;
- }
-
- if (policy != SCHED_OTHER)
- {
- errno = ENOTSUP;
- return -1;
+ return EINVAL;
}
#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL)
@@ -278,14 +263,7 @@ sched_get_priority_min(int policy)
{
if (policy < SCHED_MIN || policy > SCHED_MAX)
{
- errno = EINVAL;
- return -1;
- }
-
- if (policy != SCHED_OTHER)
- {
- errno = ENOTSUP;
- return -1;
+ return EINVAL;
}
#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL)
@@ -299,175 +277,31 @@ sched_get_priority_min(int policy)
int
-sched_rr_get_interval(pid_t pid, struct timespec * interval)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * This function updates the timespec structure
- * referenced by the interval argument to contain
- * the current quantum for the process executing
- * under the SCHED_RR policy. If a process, running under
- * the round-robin scheduling policy, runs without
- * blocking or yielding for more than this amount of
- * time, it may be preempted by another runnable
- * process (at the same priority).
- *
- * If the PID argument is zero, the current execution
- * time limit for the calling process is returned.
- *
- * PARAMETERS
- * pid Process identifier.
- *
- *
- * DESCRIPTION
- * This function updates the timespec structure
- * referenced by the interval argument to contain
- * the current quantum for the process executing
- * under the SCHED_RR policy. If a process, running under
- * the round-robin scheduling policy, runs without
- * blocking or yielding for more than this amount of
- * time, it may be preempted by another runnable
- * process (at the same priority).
- *
- * If the PID argument is zero, the current execution
- * time limit for the calling process is returned.
- *
- * RESULTS
- * We don't support SCHED_RR so this routine always fails.
- *
- * 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.
- *
- * errno: ESRCH Pid doesn't refer to a valid process.
- * EPERM The process referenced by pid does
- * not allow query access.
- * ENOTSUP SCHED_RR is not supported.
- *
- * ------------------------------------------------------
- */
-{
- /*
- * Provide other valid side-effects
- * such as EPERM and ESRCH errors.
- */
- if (0 != pid)
- {
- DWORD selfPid = GetCurrentProcessId();
-
- if (pid != selfPid)
- {
- HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
-
- if (NULL == h)
- {
- errno = (GetLastError() == (0xFF & ERROR_ACCESS_DENIED)
- ? EPERM
- : ESRCH );
-
- return -1;
- }
-
- (void) CloseHandle(h);
- }
- }
-
- /*
- * We can't return ENOSYS and stay strictly compliant with the
- * standard. We don't support round-robin scheduling so
- * we return ENOTSUP instead. This is consistent with
- * routines which return ENOTSUP if SCHED_RR is given
- * as the policy parameter.
- */
- errno = ENOTSUP;
- return -1;
-}
-
-
-int
sched_setscheduler(pid_t pid, int policy)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * This function returns sets the scheduling policy and
- * scheduling parameters of the process specified by pid
- * to policy and the parameters specified in the
- * sched_param structure pointed to by param, respectively.
- * The value of the sched_priority member in the sched_param
- * structure is any integer within the inclusive priority
- * range for the scheduling policy specified by policy.
- * If the value of pid is negative, the behaviour of the
- * sched_setscheduler() function is unspecified.
- *
- * PARAMETERS
- * pid Identifier of the process in which the
- * policy will be set.
- * policy The new policy value.
- *
- *
- * DESCRIPTION
- * This function returns sets the scheduling policy and
- * scheduling parameters of the process specified by pid
- * to policy and the parameters specified in the
- * sched_param structure pointed to by param, respectively.
- * The value of the sched_priority member in the sched_param
- * structure is any integer within the inclusive priority
- * range for the scheduling policy specified by policy.
- * If the value of pid is negative, the behaviour of the
- * sched_setscheduler() function is unspecified.
- *
- * RESULTS
- * SCHED_OTHER on success this is the only possible
- * value that can be returned.
- *
- * 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.
- *
- * errno: ESRCH 'pid' doesn't refer to an existing
- * process.
- * EPERM The process referenced by pid does
- * not allow set access.
- * EINVAL 'policy' is not a valid policy value.
- * ENOSYS the policy specified is not supported.
- *
- * ------------------------------------------------------
- */
{
/*
* Win32 only has one policy which we call SCHED_OTHER.
* However, we try to provide other valid side-effects
- * such as EPERM and ESRCH errors.
+ * such as EPERM and ESRCH errors. Choosing to check
+ * for a valid policy last allows us to get the most value out
+ * of this function.
*/
if (0 != pid)
{
- DWORD selfPid = GetCurrentProcessId();
+ int selfPid = (int) GetCurrentProcessId();
if (pid != selfPid)
{
- HANDLE h = OpenProcess(PROCESS_SET_INFORMATION, FALSE, pid);
+ HANDLE h = OpenProcess(PROCESS_SET_INFORMATION, FALSE, (DWORD) pid);
if (NULL == h)
{
- errno = (GetLastError() == (0xFF & ERROR_ACCESS_DENIED)
- ? EPERM
- : ESRCH );
-
+ errno = (GetLastError() == (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH;
return -1;
}
-
- (void) CloseHandle(h);
}
}
- if (policy < SCHED_MIN || policy > SCHED_MAX)
- {
- errno = EINVAL;
- return -1;
- }
-
if (SCHED_OTHER != policy)
{
errno = ENOSYS;
@@ -484,39 +318,6 @@ sched_setscheduler(pid_t pid, int policy)
int
sched_getscheduler(pid_t pid)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * This function returns the scheduling policy of the
- * process specified by pid. If the value of pid is
- * negative, the behaviour of the sched_getscheduler()
- * function is unspecified.
- *
- * PARAMETERS
- * pid Process identifier.
- *
- *
- * DESCRIPTION
- * This function returns the scheduling policy of the
- * process specified by pid. If the value of pid is
- * negative, the behaviour of the sched_getscheduler()
- * function is unspecified.
- *
- * RESULTS
- * SCHED_OTHER on success this is the only possible
- * value that can be returned.
- *
- * 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.
- *
- * errno: ESRCH Pid doesn't refer to a valid process.
- * EPERM The process referenced by pid does
- * not allow query access.
- *
- * ------------------------------------------------------
- */
{
/*
* Win32 only has one policy which we call SCHED_OTHER.
@@ -525,22 +326,17 @@ sched_getscheduler(pid_t pid)
*/
if (0 != pid)
{
- DWORD selfPid = GetCurrentProcessId();
+ int selfPid = (int) GetCurrentProcessId();
if (pid != selfPid)
{
- HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
+ HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD) pid);
if (NULL == h)
{
- errno = (GetLastError() == (0xFF & ERROR_ACCESS_DENIED)
- ? EPERM
- : ESRCH );
-
+ errno = (GetLastError() == (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH;
return -1;
}
-
- (void) CloseHandle(h);
}
}
@@ -569,7 +365,8 @@ sched_yield(void)
* error.
*
* RESULTS
- * 0 always succeeds
+ * 0 successfully created semaphore,
+ * ENOSYS sched_yield not supported,
*
* ------------------------------------------------------
*/
diff --git a/sched.h b/sched.h
index e4e02a2..870087f 100644
--- a/sched.h
+++ b/sched.h
@@ -28,37 +28,17 @@
#ifndef _SCHED_H
#define _SCHED_H
-#if !defined( PTW32_HEADER )
-#define PTW32_HEADER
-
-#ifdef _UWIN
-# define HAVE_STRUCT_TIMESPEC 1
-# define HAVE_SIGNAL_H 1
-# undef HAVE_CONFIG_H
-# pragma comment(lib, "pthread")
-#endif
-
-#endif /* PTW32_HEADER */
-
#if defined(__MINGW32__) || defined(_UWIN)
/* For pid_t */
# include <sys/types.h>
-/* Required by Unix 98 - including sched.h makes time.h available */
+/* Required by Unix 98 */
# include <time.h>
#else
-typedef DWORD pid_t;
+typedef int pid_t;
#endif
-#if ! defined(HAVE_STRUCT_TIMESPEC) && ! defined(PTW32_TIMESPEC)
-#define PTW32_TIMESPEC
-struct timespec {
- long tv_sec;
- long tv_nsec;
-};
-#endif /* HAVE_STRUCT_TIMESPEC */
-
-
/* Thread scheduling policies */
+
enum {
SCHED_OTHER = 0,
SCHED_FIFO,
@@ -86,7 +66,9 @@ int sched_setscheduler (pid_t pid, int policy);
int sched_getscheduler (pid_t pid);
-int sched_rr_get_interval(pid_t pid, struct timespec * interval);
+#define sched_rr_get_interval(_pid, _interval) \
+ ( errno = ENOSYS, (int) -1 )
+
#ifdef __cplusplus
} /* End of extern "C" */
@@ -94,3 +76,4 @@ int sched_rr_get_interval(pid_t pid, struct timespec * interval);
#endif /* !_SCHED_H */
+
diff --git a/semaphore.c b/semaphore.c
index 9f80f77..81b777f 100644
--- a/semaphore.c
+++ b/semaphore.c
@@ -121,10 +121,10 @@ sem_init (sem_t * sem, int pshared, unsigned int value)
#else /* NEED_SEM */
- s->sem = CreateSemaphore (0,
- value,
- 0x7FFFFFF,
- NULL);
+ s->sem = CreateSemaphore (NULL, /* Always NULL */
+ value, /* Initial value */
+ 0x7FFFFFFFL, /* Maximum value */
+ NULL); /* Name */
if (0 == s->sem)
{
@@ -464,6 +464,71 @@ sem_post (sem_t * sem)
int
+sem_post_multiple (sem_t * sem, int count )
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function posts multiple wakeups to a semaphore.
+ *
+ * PARAMETERS
+ * sem
+ * pointer to an instance of sem_t
+ *
+ * count
+ * counter, must be greater than or equal to zero.
+ *
+ * DESCRIPTION
+ * This function posts multiple wakeups to a semaphore. If there
+ * are waiting threads (or processes), n <= count are awakened;
+ * the semaphore value is incremented by count - n.
+ *
+ * RESULTS
+ * 0 successfully posted semaphore,
+ * -1 failed, error in errno
+ * ERRNO
+ * EINVAL 'sem' is not a valid semaphore
+ * or count is less than zero.
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+
+ if (sem == NULL || *sem == NULL || count < 0)
+ {
+ result = EINVAL;
+ }
+ else if (count == 0)
+ {
+ return 0;
+ }
+
+#ifdef NEED_SEM
+
+ else if (! ptw32_increase_semaphore (sem, count))
+
+#else /* NEED_SEM */
+
+ else if (! ReleaseSemaphore ((*sem)->sem, count, 0))
+
+#endif /* NEED_SEM */
+
+ {
+ result = EINVAL;
+ }
+
+ if (result != 0)
+ {
+ errno = result;
+ return -1;
+ }
+
+ return 0;
+
+} /* sem_post_multiple */
+
+
+int
sem_open (const char * name, int oflag, mode_t mode, unsigned int value)
{
errno = ENOSYS;
diff --git a/semaphore.h b/semaphore.h
index 71679dd..8bb9b64 100644
--- a/semaphore.h
+++ b/semaphore.h
@@ -69,36 +69,30 @@ typedef struct sem_t_ * sem_t;
int sem_init (sem_t * sem,
int pshared,
- unsigned int value
- );
+ unsigned int value);
-int sem_destroy (sem_t * sem
- );
+int sem_destroy (sem_t * sem);
-int sem_trywait (sem_t * sem
- );
+int sem_trywait (sem_t * sem);
-int sem_wait (sem_t * sem
- );
+int sem_wait (sem_t * sem);
-int sem_post (sem_t * sem
- );
+int sem_post (sem_t * sem);
+
+int sem_post_multiple (sem_t * sem,
+ int count);
int sem_open (const char * name,
int oflag,
mode_t mode,
- unsigned int value
- );
+ unsigned int value);
-int sem_close (sem_t * sem
- );
+int sem_close (sem_t * sem);
-int sem_unlink (const char * name
- );
+int sem_unlink (const char * name);
int sem_getvalue (sem_t * sem,
- int * sval
- );
+ int * sval);
#ifdef __cplusplus
} /* End of extern "C" */