From c156eacc8b9c6f33f89c7563f2821320be79c2e1 Mon Sep 17 00:00:00 2001 From: rpj Date: Sun, 1 Jul 2001 14:35:49 +0000 Subject: 2001-07-01 Ross Johnson 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. --- ANNOUNCE | 71 ++++++++++++-- ChangeLog | 12 +++ Nmakefile.tests | 290 +++++++++++++++++++++++++++++--------------------------- condvar.c | 121 ++++++++--------------- pthread.def | 7 +- pthread.h | 15 +-- sched.c | 239 ++++------------------------------------------ sched.h | 31 ++---- semaphore.c | 73 +++++++++++++- semaphore.h | 30 +++--- 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 + + 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 * 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 -#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) @@ -298,176 +276,32 @@ 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 -/* Required by Unix 98 - including sched.h makes time.h available */ +/* Required by Unix 98 */ # include #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) { @@ -463,6 +463,71 @@ sem_post (sem_t * sem) } /* sem_post */ +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) { 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" */ -- cgit v1.2.3