diff options
| -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" */ | 
