diff options
author | rpj <rpj> | 2001-07-01 14:35:49 +0000 |
---|---|---|
committer | rpj <rpj> | 2001-07-01 14:35:49 +0000 |
commit | c156eacc8b9c6f33f89c7563f2821320be79c2e1 (patch) | |
tree | e43c9e4dcfc56577e2dac01c39d4a10ea91c5dc4 | |
parent | 19299847fdd32094b28377db1aea61b0f605dc8b (diff) |
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.
-rw-r--r-- | ANNOUNCE | 71 | ||||
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | Nmakefile.tests | 290 | ||||
-rw-r--r-- | condvar.c | 121 | ||||
-rw-r--r-- | pthread.def | 7 | ||||
-rw-r--r-- | pthread.h | 15 | ||||
-rw-r--r-- | sched.c | 239 | ||||
-rw-r--r-- | sched.h | 31 | ||||
-rw-r--r-- | semaphore.c | 73 | ||||
-rw-r--r-- | semaphore.h | 30 |
10 files changed, 378 insertions, 511 deletions
@@ -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
@@ -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
+
@@ -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
@@ -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 *); @@ -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, * * ------------------------------------------------------ */ @@ -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" */ |