From af1871fba4fc253b5a31e4a0eed667fe79f534d7 Mon Sep 17 00:00:00 2001 From: rpj Date: Thu, 18 Sep 2003 02:31:39 +0000 Subject: Cleanup and fixes to thread priority management. Other minor changes. --- ANNOUNCE | 2 +- ChangeLog | 39 +++++ NEWS | 40 +++-- Nmakefile.tests | 11 +- README | 252 +++++++++++++++-------------- README.NONPORTABLE | 407 ++++++++++++++++++++++++++++++----------------- create.c | 58 ++++--- implement.h | 6 + pthread_getschedparam.c | 17 +- pthread_self.c | 6 + pthread_setschedparam.c | 55 ++++++- ptw32_new.c | 20 +-- sched_get_priority_max.c | 67 +++++++- sched_get_priority_min.c | 68 +++++++- tests/ChangeLog | 27 +++- tests/GNUmakefile | 24 ++- tests/Makefile | 29 ++-- tests/README.benchtests | 163 +++++++++++-------- tests/SIZES.GC | 20 +++ tests/SIZES.GCE | 20 +++ tests/SIZES.VC | 20 +++ tests/benchlib.c | 338 +++++++++++++++++++++++++++++++++++++++ tests/benchtest.h | 295 +--------------------------------- tests/benchtest1.c | 23 +-- tests/benchtest2.c | 2 +- tests/benchtest5.c | 20 +-- tests/inherit1.c | 17 +- tests/priority1.c | 21 ++- tests/priority2.c | 35 ++-- tests/sizes.c | 28 ++++ 30 files changed, 1375 insertions(+), 755 deletions(-) create mode 100755 tests/SIZES.GC create mode 100755 tests/SIZES.GCE create mode 100755 tests/SIZES.VC create mode 100644 tests/benchlib.c create mode 100644 tests/sizes.c diff --git a/ANNOUNCE b/ANNOUNCE index 9e504e6..a05d6ea 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -1,4 +1,4 @@ - PTHREADS-WIN32 SNAPSHOT 2003-09-04 + PTHREADS-WIN32 SNAPSHOT 2003-09-18 ---------------------------------- Web Site: http://sources.redhat.com/pthreads-win32/ FTP Site: ftp://sources.redhat.com/pub/pthreads-win32 diff --git a/ChangeLog b/ChangeLog index 70ce334..b26b8b8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,42 @@ +2003-09-14 Ross Johnson + + * pthread_setschedparam.c (pthread_setschedparam): Attempt to map + all priority levels between max and min (as returned by + sched_get_priority_min/max) to reasonable Win32 priority levels - i.e. + levels between THREAD_PRIORITY_LOWEST/IDLE to THREAD_PRIORITY_LOWEST and + between THREAD_PRIORITY_HIGHEST/TIME_CRITICAL to THREAD_PRIORITY_HIGHEST + while others remain unchanged; record specified thread priority level + for return by pthread_getschedparam. + + Note that, previously, specified levels not matching Win32 priority levels + would silently leave the current thread priority unaltered. + + * pthread_getschedparam.c (pthread_getschedparam): Return the priority + level specified by the latest pthread_setschedparam or pthread_create rather + than the actual running thread priority as returned by GetThreadPriority - as + required by POSIX. I.e. temporary or adjusted actual priority levels are not + returned by this routine. + + * pthread_create.c (pthread_create): For priority levels specified via + pthread attributes, attempt to map all priority levels between max and + min (as returned by sched_get_priority_min/max) to reasonable Win32 + priority levels; record priority level given via attributes, or + inherited from parent thread, for later return by pthread_getschedparam. + + * ptw32_new.c (ptw32_new): Initialise pthread_t_ sched_priority element. + + * pthread_self.c (pthread_self): Set newly created implicit POSIX thread + sched_priority to Win32 thread's current actual priority. Temporarily + altered priorities can't be avoided in this case. + + * implement.h (struct pthread_t_): Add new sched_priority element. + +2003-09-12 Ross Johnson + + * sched_get_priority_min.c (sched_get_priority_min): On error should return -1 + with errno set. + * sched_get_priority_max.c (sched_get_priority_max): Likewise. + 2003-09-03 Ross Johnson * w32_cancelableWait.c (ptw32_cancelable_wait): Allow cancelation diff --git a/NEWS b/NEWS index 04d8483..008f8f2 100644 --- a/NEWS +++ b/NEWS @@ -1,15 +1,35 @@ -SNAPSHOT 2003-09-04 +SNAPSHOT 2003-09-18 ------------------- +Cleanup of thread priority management. In particular, setting of thread +priority now attempts to map invalid Win32 values within the range returned +by sched_get_priority_min/max() to useful values. See README.NONPORTABLE +under "Thread priority". + Bug fixes --------- -* ptw32_cancelableWait() now allows cancelation of waiting implicit POSIX -threads. +* pthread_getschedparam() now returns the priority given by the most recent +call to pthread_setschedparam() or established by pthread_create(), as +required by the standard. Previously, pthread_getschedparam() incorrectly +returned the running thread priority at the time of the call, which may have +been adjusted or temporarily promoted/demoted. + +* sched_get_priority_min() and sched_get_priority_max() now return -1 on error +and set errno. Previously, they incorrectly returned the error value directly. + + +SNAPSHOT 2003-09-04 +------------------- + +Bug fixes +--------- +* ptw32_cancelableWait() now allows cancelation of waiting implicit POSIX +threads. -New test --------- -* cancel8.c tests cancelation of Win32 threads waiting at a POSIX cancelation -point. +New test +-------- +* cancel8.c tests cancelation of Win32 threads waiting at a POSIX cancelation +point. SNAPSHOT 2003-09-03 @@ -53,9 +73,9 @@ needs a pthread_t as a parameter of course). A Win32 thread can discover it's ow POSIX thread ID by calling pthread_self(), which will create the handle if necessary and return the pthread_t value. -New tests ---------- -Test the above new feature. +New tests +--------- +Test the above new feature. SNAPSHOT 2003-08-19 diff --git a/Nmakefile.tests b/Nmakefile.tests index 9a9f9a5..8353197 100644 --- a/Nmakefile.tests +++ b/Nmakefile.tests @@ -18,6 +18,7 @@ set keepgoing $(I:D:B:S=.pass) : .VIRTUAL .FORCE $(I) $(>) end +sizes:: sizes.c loadfree:: loadfree.c mutex1:: mutex1.c mutex1e:: mutex1e.c @@ -57,6 +58,7 @@ equal1:: equal1.c exit2:: exit2.c exit3:: exit3.c exit4:: exit4.c +exit5:: exit5.c join0:: join0.c join1:: join1.c join2:: join2.c @@ -97,6 +99,7 @@ cancel4:: cancel4.c cancel5:: cancel5.c cancel6a:: cancel6a.c cancel6d:: cancel6d.c +cancel7:: cancel7.c cleanup0:: cleanup0.c cleanup1:: cleanup1.c cleanup2:: cleanup2.c @@ -124,6 +127,7 @@ benchtest5:: benchtest5.c valid1:: valid1.c valid2:: valid2.c +sizes: :test: sizes loadfree: :test: semaphore1 :test: loadfree semaphore2 :test: loadfree @@ -161,6 +165,8 @@ mutex8r :test: mutex7r equal1 :test: create1 exit2 :test: create1 exit3 :test: create1 +exit4 :test: kill1 +exit5 :test: exit4 join0 :test: create1 join1 :test: create1 join2 :test: create1 @@ -196,8 +202,9 @@ context1 :test: cancel2 cancel3 :test: context1 cancel4 :test: cancel3 cancel5 :test: cancel3 -cancel6a :test: cancel3 -cancel6d :test: cancel3 +cancel6a :test: cancel3 +cancel6d :test: cancel3 +cancel7 :test: kill1 cleanup0 :test: cancel5 cleanup1 :test: cleanup0 cleanup2 :test: cleanup1 diff --git a/README b/README index b669f81..fc7c2f6 100644 --- a/README +++ b/README @@ -11,15 +11,68 @@ What is it? ----------- Pthreads-win32 is an Open Source Software implementation of the -Threads component of the POSIX 1003.1c 1995 Standard for Microsoft's -Win32 environment. Some functions from POSIX 1003.1b are also -supported including semaphores. Other related functions include -the set of read-write lock functions. The library also supports -some of the functionality of the Open Group's Single Unix -specification, version 2, namely mutex types. +Threads component of the POSIX 1003.1c 1995 Standard (or later) +for Microsoft's Win32 environment. Some functions from POSIX +1003.1b are also supported including semaphores. Other related +functions include the set of read-write lock functions. The +library also supports some of the functionality of the Open +Group's Single Unix specification, version 2, namely mutex types, +plus some common and pthreads-win32 specific non-portable +routines (see README.NONPORTABLE). See the file "ANNOUNCE" for more information including standards -conformance details and list of supported routines. +conformance details and the list of supported and unsupported +routines. + + +Library naming +-------------- + +Because the library is being built using various exception +handling schemes and compilers - and because the library +may not work reliably if these are mixed in an application, +each different version of the library has it's own name. + +Note 1: the incompatibility is really between EH implementations +of the different compilers. It should be possible to use the +standard C version from either compiler with C++ applications +built with a different compiler. If you use an EH version of +the library, then you must use the same compiler for the +application. This is another complication and dependency that +can be avoided by using only the standard C library version. + +Note 2: if you use a standard C pthread*.dll with a C++ +application, then any functions that you define that are +intended to be called via pthread_cleanup_push() must be +__cdecl. + +Note 3: the intention is to also name either the VC or GC +version (it should be arbitrary) as pthread.dll, including +pthread.lib and libpthread.a as appropriate. + +In general: + pthread[VG]{SE,CE,C}.dll + pthread[VG]{SE,CE,C}.lib + +where: + [VG] indicates the compiler + V - MS VC + G - GNU C + + {SE,CE,C} indicates the exception handling scheme + SE - Structured EH + CE - C++ EH + C - no exceptions - uses setjmp/longjmp + +For example: + pthreadVSE.dll (MSVC/SEH) + pthreadGCE.dll (GNUC/C++ EH) + pthreadGC.dll (GNUC/not dependent on exceptions) + +The GNU library archive file names have changed to: + + libpthreadGCE.a + libpthreadGC.a Which of the several dll versions to use? @@ -35,15 +88,15 @@ use MSVC. Otherwise, you need to choose carefully and know WHY. The most important choice you need to make is whether to use a -version that uses exceptions internally, or not (there are versions +version that uses exceptions internally, or not. There are versions of the library that use exceptions as part of the thread -cancelation and exit implementation, and one that uses -setjmp/longjmp instead). +cancelation and exit implementation. The default version uses +setjmp/longjmp. There is some contension amongst POSIX threads experts as to how POSIX threads cancelation and exit should work -with languages that include exceptions and handlers, e.g. -C++ and even C (Microsoft's Structured Exceptions). +with languages that use exceptions, e.g. C++ and even C +(Microsoft's Structured Exceptions). The issue is: should cancelation of a thread in, say, a C++ application cause object destructors and C++ exception @@ -52,8 +105,8 @@ exit, or not? There seems to be more opinion in favour of using the standard C version of the library (no EH) with C++ applications -since this appears to be the assumption commercial pthreads -implementations make. Therefore, if you use an EH version +for the reason that this appears to be the assumption commercial +pthreads implementations make. Therefore, if you use an EH version of pthreads-win32 then you may be under the illusion that your application will be portable, when in fact it is likely to behave differently when linked with other pthreads libraries. @@ -63,19 +116,14 @@ the library? There are a couple of reasons: - there is division amongst the experts and so the code may - be needed in the future. (Yes, it's in the repository and we - can get it out anytime in the future, but ...) + be needed in the future. Yes, it's in the repository and we + can get it out anytime in the future, but it would be difficult + to find. - pthreads-win32 is one of the few implementations, and possibly the only freely available one, that has EH versions. It may be useful to people who want to play with or study application behaviour under these conditions. -Finally, for a proper version of the library with no internal -exceptions to be usable with C++ applications, the C version -should be compiled as C++ so that it knows about and can propagate -exceptions even if it doesn't use C++ features. - - Notes: [If you use either pthreadVCE or pthreadGCE] @@ -105,56 +153,6 @@ whereby you may not have multiple handlers for the same exception in the same try/catch block. GNU G++ doesn't have this restriction. -Library naming --------------- - -Because the library is being built using various exception -handling schemes and compilers - and because the library -may not work reliably if these are mixed in an application, -each different version of the library has it's own name. - -Note 1: the incompatibility is really between EH implementations -of the different compilers. It should be possible to use the -standard C version from either compiler with C++ applications -built with a different compiler. If you use an EH version of -the library, then you must use the same compiler for the -application. This is another complication and dependency that -can be avoided by using only the standard C library version. - -Note 2: if you use a standard C pthread*.dll with a C++ -application, then any functions that you define that are -intended to be called via pthread_cleanup_push() must be -__cdecl. - -Note 3: the intention is to also name either the VC or GC -version (it should be arbitrary) as pthread.dll, including -pthread.lib and libpthread.a as appropriate. - -In general: - pthread[VG]{SE,CE,C}.dll - pthread[VG]{SE,CE,C}.lib - -where: - [VG] indicates the compiler - V - MS VC - G - GNU C - - {SE,CE,C} indicates the exception handling scheme - SE - Structured EH - CE - C++ EH - C - no exceptions - uses setjmp/longjmp - -For example: - pthreadVSE.dll (MSVC/SEH) - pthreadGCE.dll (GNUC/C++ EH) - pthreadGC.dll (GNUC/not dependent on exceptions) - -The GNU library archive file names have changed to: - - libpthreadGCE.a - libpthreadGC.a - - Other name changes ------------------ @@ -253,28 +251,28 @@ Building under VC++ using C++ EH, Structured EH, or just C From the source directory run one of the following: -nmake clean VCE (builds the VC++ C++ EH version pthreadVCE.dll) +nmake clean VC (builds the VC setjmp/longjmp version of pthreadVC.dll) or: -nmake clean VSE (builds the VC++ structured EH version pthreadVSE.dll) +nmake clean VCE (builds the VC++ C++ EH version pthreadVCE.dll) or: -nmake clean VC (builds the VC setjmp/longjmp version of pthreadVC.dll) +nmake clean VSE (builds the VC++ structured EH version pthreadVSE.dll) You can run the testsuite by changing to the "tests" directory and running the target corresponding to the DLL version you built: -nmake clean VCE +nmake clean VC or: -nmake clean VSE +nmake clean VCE or: -nmake clean VC +nmake clean VSE or: @@ -285,25 +283,26 @@ nmake clean VCX (tests the VC version of the library with C++ (EH) Building under Mingw32 ---------------------- -The dll can be built with Mingw32 gcc-2.95.2-1 after you've -made the changes to Mingw32 desribed in Question 6 of the FAQ. +The dll can be built easily with recent versions of Mingw32. +(The distributed versions are built using Mingw32 and MsysDTK +from www.mingw32.org.) From the source directory, run -make clean GCE +make clean GC or: -make clean GC +make clean GCE You can run the testsuite by changing to the "tests" directory and running -make clean GCE +make clean GC or: -make clean GC +make clean GCE or: @@ -331,41 +330,47 @@ from the FTP site (see under "Availability" below): semaphore.h sched.h pthread.def - pthreadVCE.dll - built with MSVC++ compiler using C++ EH - pthreadVCE.lib pthreadVC.dll - built with MSVC compiler using C setjmp/longjmp pthreadVC.lib + pthreadVCE.dll - built with MSVC++ compiler using C++ EH + pthreadVCE.lib pthreadVSE.dll - built with MSVC compiler using SEH pthreadVSE.lib - pthreadGCE.dll - built with Mingw32 G++ - pthreadGCE.a - derived from pthreadGCE.dll pthreadGC.dll - built with Mingw32 GCC - pthreadGC.a - derived from pthreadGC.dll + libpthreadGC.a - derived from pthreadGC.dll + pthreadGCE.dll - built with Mingw32 G++ + libpthreadGCE.a - derived from pthreadGCE.dll + +As of August 2003 pthreads-win32 pthreadG* versions are built and tested +using the MinGW + MsysDTK environment current as of that date or later. +The following file MAY be needed for older MinGW environments. -As of August 2003 pthreads-win32 is built and tested using the MinGW + MsysDTK -environment current as of that date or later. The following file MAY be needed -for older MinGW environments. gcc.dll - needed to build and run applications that use pthreadGCE.dll. -Building applications with the library --------------------------------------- +Building applications with GNU compilers +---------------------------------------- -Use the appropriate DLL and LIB files to match the exception handing -that you use in your application, or specifically, in your POSIX -threads. Don't mix them or neither thread cancelation nor -pthread_exit() will work reliably if at all. +If you're using pthreadGC.dll: -If in doubt use the C (no-exceptions) versions of the library. +With the three header files, pthreadGC.dll and libpthreadGC.a in the +same directory as your application myapp.c, you could compile, link +and run myapp.c under Mingw32 as follows: + gcc -o myapp.exe myapp.c -I. -L. -lpthreadGC + myapp -Building applications with GNU compilers ----------------------------------------- +Or put pthreadGC.dll in an appropriate directory in your PATH, +put libpthreadGC.a in your system lib directory, and +put the three header files in your system include directory, +then use: -If you're using pthreadGCE.dll: + gcc -o myapp.exe myapp.c -lpthreadGC + myapp -Use gcc-2.95.2-1 or later modified as per pthreads-win32 FAQ question 11. + +If you're using pthreadGCE.dll: With the three header files, pthreadGCE.dll, gcc.dll and libpthreadGCE.a in the same directory as your application myapp.c, you could compile, @@ -375,30 +380,13 @@ link and run myapp.c under Mingw32 as follows: myapp Or put pthreadGCE.dll and gcc.dll in an appropriate directory in -your PATH, put libpthreadGCE.a in MINGW_ROOT\i386-mingw32\lib, and -put the three header files in MINGW_ROOT\i386-mingw32\include, +your PATH, put libpthreadGCE.a in your system lib directory, and +put the three header files in your system include directory, then use: gcc -x c++ -o myapp.exe myapp.c -lpthreadGCE myapp -If you're using pthreadGC.dll: - -With the three header files, pthreadGC.dll and libpthreadGC.a in the -same directory as your application myapp.c, you could compile, link -and run myapp.c under Mingw32 as follows: - - gcc -o myapp.exe myapp.c -I. -L. -lpthreadGC - myapp - -Or put pthreadGC.dll in an appropriate directory in your PATH, -put libpthreadGC.a in MINGW_ROOT\i386-mingw32\lib, and -put the three header files in MINGW_ROOT\i386-mingw32\include, -then use: - - gcc -o myapp.exe myapp.c -lpthreadGC - myapp - Availability ------------ @@ -436,20 +424,30 @@ Acknowledgements Pthreads-win32 is based substantially on a Win32 Pthreads implementation contributed by John E. Bossom. + Many others have contributed important new code, improvements and bug fixes. Thanks go to Alexander Terekhov -and Louis Thomas for their improvements to the implementation -of condition variables. +and Louis Thomas for their implementation of condition variables +(see README.CV). + +Thanks also to the authors of the following paper, which served as +the first CV design, and which identifies the important issues: +"Strategies for Implementing POSIX Condition Variables on Win32" +- http://www.cs.wustl.edu/~schmidt/win32-cv-1.html See the 'CONTRIBUTORS' file for the list of contributors. -As much as possible, the ChangeLog file also attributes +As much as possible, the ChangeLog file attributes contributions and patches that have been incorporated -in the library. +in the library to the individuals responsible. + +Finally, thanks to all those who work on and contribute to the +POSIX and Single Unix Specification standards. The maturity of an +industry can be measured by it's open standards. ---- Ross Johnson - + diff --git a/README.NONPORTABLE b/README.NONPORTABLE index 0985097..12336bd 100644 --- a/README.NONPORTABLE +++ b/README.NONPORTABLE @@ -1,149 +1,258 @@ -Non-portable functions included in pthreads-win32 -------------------------------------------------- - -void * -pthread_timechange_handler_np(void *) - - To improve tolerance against operator or time service - initiated system clock changes. - - This routine can be called by an application when it - receives a WM_TIMECHANGE message from the system. At - present it broadcasts all condition variables so that - waiting threads can wake up and re-evaluate their - conditions and restart their timed waits if required. - - It has the same return type and argument type as a - thread routine so that it may be called directly - through pthread_create() for asynchronicity. - - Parameters - - Although a parameter must be supplied, it is ignored. - The value NULL can be used. - - Return values - - It can return an error EAGAIN to indicate that not - all condition variables were broadcast for some reason. - Otherwise, 0 is returned. - - If run as a thread, the return value is returned - through pthread_join(), otherwise directly. - - The return value should be cast to an integer. - - -HANDLE -pthread_getw32threadhandle_np(pthread_t thread); - - Returns the win32 thread handle that the POSIX - thread "thread" is running as. - - Applications can use the win32 handle to set - win32 specific attributes of the thread. - - -int -pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, int kind) - -int -pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, int *kind) - - These two routines are included for Linux compatibility - and are direct equivalents to the standard routines - pthread_mutexattr_settype - pthread_mutexattr_gettype - - pthread_mutexattr_setkind_np accepts the following - mutex kinds: - PTHREAD_MUTEX_FAST_NP - PTHREAD_MUTEX_ERRORCHECK_NP - PTHREAD_MUTEX_RECURSIVE_NP - - These are really just equivalent to (respectively): - PTHREAD_MUTEX_NORMAL - PTHREAD_MUTEX_ERRORCHECK - PTHREAD_MUTEX_RECURSIVE - -int -pthread_delay_np (const struct timespec *interval); - - This routine causes a thread to delay execution for a specific period of time. - This period ends at the current time plus the specified interval. The routine - will not return before the end of the period is reached, but may return an - arbitrary amount of time after the period has gone by. This can be due to - system load, thread priorities, and system timer granularity. - - Specifying an interval of zero (0) seconds and zero (0) nanoseconds is - allowed and can be used to force the thread to give up the processor or to - deliver a pending cancelation request. - - This routine is a cancelation point. - - The timespec structure contains the following two fields: - - tv_sec is an integer number of seconds. - tv_nsec is an integer number of nanoseconds. - - Return Values - - If an error condition occurs, this routine returns an integer value - indicating the type of error. Possible return values are as follows: - - 0 Successful completion. - [EINVAL] The value specified by interval is invalid. - -int -pthread_num_processors_np - - This routine (found on HPUX systems) returns the number of processors - in the system. This implementation actually returns the number of - processors available to the process, which can be a lower number - than the system's number, depending on the process's affinity mask. - -BOOL -pthread_win32_process_attach_np (void); - -BOOL -pthread_win32_process_detach_np (void); - -BOOL -pthread_win32_thread_attach_np (void); - -BOOL -pthread_win32_thread_detach_np (void); - - These functions contain the code normally run via dllMain - when the library is used as a dll but which need to be - called explicitly by an application when the library - is statically linked. - - You will need to call pthread_win32_process_attach_np() before - you can call any pthread routines when statically linking. - You should call pthread_win32_process_detach_np() before - exiting your application to clean up. - - pthread_win32_thread_attach_np() is currently a no-op, but - pthread_win32_thread_detach_np() is needed to clean up - the implicit pthread handle that is allocated to a Win32 thread if - it calls certain pthreads routines. Call this routine when the - Win32 thread exits. - - These functions invariably return TRUE except for - pthread_win32_process_attach_np() which will return FALSE - if pthreads-win32 initialisation fails. - -int -pthreadCancelableWait (HANDLE waitHandle); - -int -pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout); - - These two functions provide hooks into the pthread_cancel - mechanism that will allow you to wait on a Windows handle - and make it a cancellation point. Both functions block - until either the given w32 handle is signaled, or - pthread_cancel has been called. It is implemented using - WaitForMultipleObjects on 'waitHandle' and a manually - reset w32 event used to implement pthread_cancel. +This file documents non-portable functions and other issues. + +Non-portable functions included in pthreads-win32 +------------------------------------------------- + +void * +pthread_timechange_handler_np(void *) + + To improve tolerance against operator or time service + initiated system clock changes. + + This routine can be called by an application when it + receives a WM_TIMECHANGE message from the system. At + present it broadcasts all condition variables so that + waiting threads can wake up and re-evaluate their + conditions and restart their timed waits if required. + + It has the same return type and argument type as a + thread routine so that it may be called directly + through pthread_create() for asynchronicity. + + Parameters + + Although a parameter must be supplied, it is ignored. + The value NULL can be used. + + Return values + + It can return an error EAGAIN to indicate that not + all condition variables were broadcast for some reason. + Otherwise, 0 is returned. + + If run as a thread, the return value is returned + through pthread_join(), otherwise directly. + + The return value should be cast to an integer. + + +HANDLE +pthread_getw32threadhandle_np(pthread_t thread); + + Returns the win32 thread handle that the POSIX + thread "thread" is running as. + + Applications can use the win32 handle to set + win32 specific attributes of the thread. + + +int +pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, int kind) + +int +pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, int *kind) + + These two routines are included for Linux compatibility + and are direct equivalents to the standard routines + pthread_mutexattr_settype + pthread_mutexattr_gettype + + pthread_mutexattr_setkind_np accepts the following + mutex kinds: + PTHREAD_MUTEX_FAST_NP + PTHREAD_MUTEX_ERRORCHECK_NP + PTHREAD_MUTEX_RECURSIVE_NP + + These are really just equivalent to (respectively): + PTHREAD_MUTEX_NORMAL + PTHREAD_MUTEX_ERRORCHECK + PTHREAD_MUTEX_RECURSIVE + +int +pthread_delay_np (const struct timespec *interval); + + This routine causes a thread to delay execution for a specific period of time. + This period ends at the current time plus the specified interval. The routine + will not return before the end of the period is reached, but may return an + arbitrary amount of time after the period has gone by. This can be due to + system load, thread priorities, and system timer granularity. + + Specifying an interval of zero (0) seconds and zero (0) nanoseconds is + allowed and can be used to force the thread to give up the processor or to + deliver a pending cancelation request. + + This routine is a cancelation point. + + The timespec structure contains the following two fields: + + tv_sec is an integer number of seconds. + tv_nsec is an integer number of nanoseconds. + + Return Values + + If an error condition occurs, this routine returns an integer value + indicating the type of error. Possible return values are as follows: + + 0 Successful completion. + [EINVAL] The value specified by interval is invalid. + +int +pthread_num_processors_np + + This routine (found on HPUX systems) returns the number of processors + in the system. This implementation actually returns the number of + processors available to the process, which can be a lower number + than the system's number, depending on the process's affinity mask. + +BOOL +pthread_win32_process_attach_np (void); + +BOOL +pthread_win32_process_detach_np (void); + +BOOL +pthread_win32_thread_attach_np (void); + +BOOL +pthread_win32_thread_detach_np (void); + + These functions contain the code normally run via dllMain + when the library is used as a dll but which need to be + called explicitly by an application when the library + is statically linked. + + You will need to call pthread_win32_process_attach_np() before + you can call any pthread routines when statically linking. + You should call pthread_win32_process_detach_np() before + exiting your application to clean up. + + pthread_win32_thread_attach_np() is currently a no-op, but + pthread_win32_thread_detach_np() is needed to clean up + the implicit pthread handle that is allocated to a Win32 thread if + it calls certain pthreads routines. Call this routine when the + Win32 thread exits. + + These functions invariably return TRUE except for + pthread_win32_process_attach_np() which will return FALSE + if pthreads-win32 initialisation fails. + +int +pthreadCancelableWait (HANDLE waitHandle); + +int +pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout); + + These two functions provide hooks into the pthread_cancel + mechanism that will allow you to wait on a Windows handle + and make it a cancellation point. Both functions block + until either the given w32 handle is signaled, or + pthread_cancel has been called. It is implemented using + WaitForMultipleObjects on 'waitHandle' and a manually + reset w32 event used to implement pthread_cancel. + + +Non-portable issues +------------------- + +Thread priority + + POSIX defines a single contiguous range of numbers that determine a + thread's priority. Win32 defines priority classes and priority + levels relative to these classes. Classes are simply priority base + levels that the defined priority levels are relative to such that, + changing a process's priority class will change the priority of all + of it's threads, while the threads retain the same relativity to each + other. + + A Win32 system defines a single contiguous monotonic range of values + that define system priority levels, just like POSIX. However, Win32 + restricts individual threads to a subset of this range on a + per-process basis. + + The following table shows the base priority levels for combinations + of priority class and priority value in Win32. + + Process Priority Class Thread Priority Level + ----------------------------------------------------------------- + 1 IDLE_PRIORITY_CLASS THREAD_PRIORITY_IDLE + 1 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + 1 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + 1 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + 1 HIGH_PRIORITY_CLASS THREAD_PRIORITY_IDLE + 2 IDLE_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + 3 IDLE_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + 4 IDLE_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + 4 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + 5 IDLE_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + 5 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + 5 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + 6 IDLE_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + 6 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + 6 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + 7 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + 7 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + 7 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + 8 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + 8 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + 8 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + 8 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + 9 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + 9 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + 9 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + 10 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + 10 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + 11 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + 11 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + 11 HIGH_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + 12 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + 12 HIGH_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + 13 HIGH_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + 14 HIGH_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + 15 IDLE_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + 15 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + 15 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + 15 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + 16 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_IDLE + 17 REALTIME_PRIORITY_CLASS -7 + 18 REALTIME_PRIORITY_CLASS -6 + 19 REALTIME_PRIORITY_CLASS -5 + 20 REALTIME_PRIORITY_CLASS -4 + 21 REALTIME_PRIORITY_CLASS -3 + 22 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + 23 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + 24 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + 25 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + 26 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + 27 REALTIME_PRIORITY_CLASS 3 + 28 REALTIME_PRIORITY_CLASS 4 + 29 REALTIME_PRIORITY_CLASS 5 + 30 REALTIME_PRIORITY_CLASS 6 + 31 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + + Windows NT: Values -7, -6, -5, -4, -3, 3, 4, 5, and 6 are not supported. + + + As you can see, the real priority levels available to any individual + Win32 thread are non-contiguous. + + An application using pthreads-win32 should not make assumptions about + the numbers used to represent thread priority levels, except that they + are monotonic between the values returned by sched_get_priority_min() + and sched_get_priority_max(). E.g. Windows 95, 98, NT, 2000, XP make + available a non-contiguous range of numbers between -15 and 15, while + at least one version of WinCE (3.0) defines the minimum priority + (THREAD_PRIORITY_LOWEST) as 5, and the maximum priority + (THREAD_PRIORITY_HIGHEST) as 1. + + Internally, pthreads-win32 maps any priority levels between + THREAD_PRIORITY_IDLE and THREAD_PRIORITY_LOWEST to THREAD_PRIORITY_LOWEST, + or between THREAD_PRIORITY_TIME_CRITICAL and THREAD_PRIORITY_HIGHEST to + THREAD_PRIORITY_HIGHEST. Currently, this also applies to + REALTIME_PRIORITY_CLASSi even if levels -7, -6, -5, -4, -3, 3, 4, 5, and 6 + are supported. + + If it wishes, a Win32 application using pthreads-win32 can use the Win32 + defined priority macros THREAD_PRIORITY_IDLE through + THREAD_PRIORITY_TIME_CRITICAL. diff --git a/create.c b/create.c index 1b3825e..cc4629b 100644 --- a/create.c +++ b/create.c @@ -87,12 +87,15 @@ pthread_create (pthread_t * tid, int run = PTW32_TRUE; ThreadParms *parms = NULL; long stackSize; + int priority; if ((thread = ptw32_new()) == NULL) { goto FAIL0; } + priority = thread->sched_priority; + if ((parms = (ThreadParms *) malloc (sizeof (*parms))) == NULL) { goto FAIL0; @@ -106,6 +109,7 @@ pthread_create (pthread_t * tid, { stackSize = (*attr)->stacksize; thread->detachState = (*attr)->detachstate; + priority = (*attr)->param.sched_priority; #if HAVE_SIGSET_T @@ -113,6 +117,36 @@ pthread_create (pthread_t * tid, #endif /* HAVE_SIGSET_T */ +#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) + /* WinCE */ +#else + /* Everything else */ + + /* + * Thread priority must be set to a valid system level + * without altering the value set by pthread_attr_setschedparam(). + */ + + /* + * PTHREAD_EXPLICIT_SCHED is the default because Win32 threads + * don't inherit their creator's priority. They are started with + * THREAD_PRIORITY_NORMAL (win32 value). The result of not supplying + * an 'attr' arg to pthread_create() is equivalent to defaulting to + * PTHREAD_EXPLICIT_SCHED and priority THREAD_PRIORITY_NORMAL. + */ + if (PTHREAD_INHERIT_SCHED == (*attr)->inheritsched) + { + /* + * If the thread that called pthread_create() is a Win32 thread + * then the inherited priority could be the result of a temporary + * system adjustment. This is not the case for POSIX threads. + */ + pthread_t self = pthread_self(); + priority = self->sched_priority; + } + +#endif + } else { @@ -150,19 +184,9 @@ pthread_create (pthread_t * tid, if (threadH != 0) { - /* - * PTHREAD_EXPLICIT_SCHED is the default because Win32 threads - * don't inherit their creator's priority. They are started with - * THREAD_PRIORITY_NORMAL (win32 value). The result of not supplying - * an 'attr' arg to pthread_create() is equivalent to defaulting to - * PTHREAD_EXPLICIT_SCHED and priority THREAD_PRIORITY_NORMAL. - */ if (attr != NULL && *attr != NULL) { - (void) SetThreadPriority(threadH, - PTHREAD_INHERIT_SCHED == (*attr)->inheritsched - ? GetThreadPriority(GetCurrentThread()) - : (*attr)->param.sched_priority ); + (void) ptw32_setthreadpriority(thread, SCHED_OTHER, priority); } if (run) @@ -204,19 +228,9 @@ pthread_create (pthread_t * tid, SuspendThread (threadH); } - /* - * PTHREAD_EXPLICIT_SCHED is the default because Win32 threads - * don't inherit their creator's priority. They are started with - * THREAD_PRIORITY_NORMAL (win32 value). The result of not supplying - * an 'attr' arg to pthread_create() is equivalent to defaulting to - * PTHREAD_EXPLICIT_SCHED and priority THREAD_PRIORITY_NORMAL. - */ if (attr != NULL && *attr != NULL) { - (void) SetThreadPriority(threadH, - PTHREAD_INHERIT_SCHED == (*attr)->inheritsched - ? GetThreadPriority(GetCurrentThread()) - : (*attr)->param.sched_priority ); + (void) ptw32_setthreadpriority(thread, SCHED_OTHER, priority); } } diff --git a/implement.h b/implement.h index ca27681..34eb826 100644 --- a/implement.h +++ b/implement.h @@ -122,6 +122,8 @@ struct pthread_t_ { void *parms; int ptErrno; int detachState; + pthread_mutex_t threadLock; /* Used for serialised access to public thread state */ + int sched_priority; /* As set, not as currently is */ pthread_mutex_t cancelLock; /* Used for async-cancel safety */ int cancelState; int cancelType; @@ -498,6 +500,10 @@ void ptw32_threadReusePush (pthread_t thread); int ptw32_getprocessors (int * count); +int ptw32_setthreadpriority (pthread_t thread, + int policy, + int priority); + #if ! defined (__MINGW32__) || defined (__MSVCRT__) unsigned __stdcall #else diff --git a/pthread_getschedparam.c b/pthread_getschedparam.c index 28800c7..ac02775 100644 --- a/pthread_getschedparam.c +++ b/pthread_getschedparam.c @@ -42,7 +42,6 @@ int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param) { - int prio; int result; /* Validate the thread id. */ @@ -64,13 +63,13 @@ pthread_getschedparam(pthread_t thread, int *policy, /* Fill out the policy. */ *policy = SCHED_OTHER; - /* Fill out the sched_param structure. */ - prio = GetThreadPriority(thread->threadH); - if (prio == THREAD_PRIORITY_ERROR_RETURN) - { - return EINVAL; - } - - param->sched_priority = prio; + /* + * This function must return the priority value set by + * the most recent pthread_setschedparam() or pthread_create() + * for the target thread. It must not return the actual thread + * priority as altered by any system priority adjustments etc. + */ + param->sched_priority = thread->sched_priority; + return 0; } diff --git a/pthread_self.c b/pthread_self.c index e7a81b8..61979cd 100644 --- a/pthread_self.c +++ b/pthread_self.c @@ -115,6 +115,12 @@ pthread_self (void) return (NULL); } #endif + + /* + * No need to explicitly serialise access to sched_priority + * because the new handle is not yet public. + */ + self->sched_priority = GetThreadPriority(self->threadH); } pthread_setspecific (ptw32_selfThreadKey, self); diff --git a/pthread_setschedparam.c b/pthread_setschedparam.c index 1741197..1447c04 100644 --- a/pthread_setschedparam.c +++ b/pthread_setschedparam.c @@ -42,7 +42,6 @@ int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param) { - int prio; int result; /* Validate the thread id. */ @@ -64,7 +63,17 @@ pthread_setschedparam(pthread_t thread, int policy, return ENOTSUP; } - prio = param->sched_priority; + return (ptw32_setthreadpriority(thread, policy, param->sched_priority)); +} + + +int +ptw32_setthreadpriority(pthread_t thread, int policy, int priority) +{ + int prio; + int result; + + prio = priority; /* Validate priority level. */ if (prio < sched_get_priority_min(policy) || @@ -73,8 +82,44 @@ pthread_setschedparam(pthread_t thread, int policy, return EINVAL; } - /* This is practically guaranteed to return TRUE. */ - (void) SetThreadPriority(thread->threadH, prio); +#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) +/* WinCE */ +#else +/* Everything else */ + + if (THREAD_PRIORITY_IDLE < prio + && THREAD_PRIORITY_LOWEST > prio) + { + prio = THREAD_PRIORITY_LOWEST; + } + else if (THREAD_PRIORITY_TIME_CRITICAL > prio + && THREAD_PRIORITY_HIGHEST < prio) + { + prio = THREAD_PRIORITY_HIGHEST; + } + +#endif + + result = pthread_mutex_lock(&thread->threadLock); + + if (0 == result) + { + /* If this fails, the current priority is unchanged. */ + if (0 == SetThreadPriority(thread->threadH, prio)) + { + result = EINVAL; + } + else + { + /* + * Must record the thread's sched_priority as given, + * not as finally adjusted. + */ + thread->sched_priority = priority; + } + + (void) pthread_mutex_unlock(&thread->threadLock); + } - return 0; + return result; } diff --git a/ptw32_new.c b/ptw32_new.c index 3e346d1..dc1d8e9 100644 --- a/ptw32_new.c +++ b/ptw32_new.c @@ -55,15 +55,17 @@ ptw32_new (void) if (t != NULL) { - t->detachState = PTHREAD_CREATE_JOINABLE; - t->cancelState = PTHREAD_CANCEL_ENABLE; - t->cancelType = PTHREAD_CANCEL_DEFERRED; - t->cancelLock = PTHREAD_MUTEX_INITIALIZER; - t->cancelEvent = CreateEvent ( - 0, - (int) PTW32_TRUE, /* manualReset */ - (int) PTW32_FALSE, /* setSignaled */ - NULL); + t->sched_priority = THREAD_PRIORITY_NORMAL; + t->detachState = PTHREAD_CREATE_JOINABLE; + t->cancelState = PTHREAD_CANCEL_ENABLE; + t->cancelType = PTHREAD_CANCEL_DEFERRED; + t->cancelLock = PTHREAD_MUTEX_INITIALIZER; + t->threadLock = PTHREAD_MUTEX_INITIALIZER; + t->cancelEvent = CreateEvent ( + 0, + (int) PTW32_TRUE, /* manualReset */ + (int) PTW32_FALSE, /* setSignaled */ + NULL); if (t->cancelEvent == NULL) { diff --git a/sched_get_priority_max.c b/sched_get_priority_max.c index a74226a..c3fb715 100644 --- a/sched_get_priority_max.c +++ b/sched_get_priority_max.c @@ -48,6 +48,70 @@ * * sched_get_priority_min() returns 5 * sched_get_priority_max() returns 1 + * + * The following table shows the base priority levels for combinations + * of priority class and priority value in Win32. + * + * Process Priority Class Thread Priority Level + * ----------------------------------------------------------------- + * 1 IDLE_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 HIGH_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 2 IDLE_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 3 IDLE_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 4 IDLE_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 4 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 5 IDLE_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 5 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 5 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 6 IDLE_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 6 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 6 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 7 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 7 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 7 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 8 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 8 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 8 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 8 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 9 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 9 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 9 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 10 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 10 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 11 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 11 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 11 HIGH_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 12 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 12 HIGH_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 13 HIGH_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 14 HIGH_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 IDLE_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 16 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 17 REALTIME_PRIORITY_CLASS -7 + * 18 REALTIME_PRIORITY_CLASS -6 + * 19 REALTIME_PRIORITY_CLASS -5 + * 20 REALTIME_PRIORITY_CLASS -4 + * 21 REALTIME_PRIORITY_CLASS -3 + * 22 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 23 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 24 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 25 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 26 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 27 REALTIME_PRIORITY_CLASS 3 + * 28 REALTIME_PRIORITY_CLASS 4 + * 29 REALTIME_PRIORITY_CLASS 5 + * 30 REALTIME_PRIORITY_CLASS 6 + * 31 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * + * Windows NT: Values -7, -6, -5, -4, -3, 3, 4, 5, and 6 are not supported. */ @@ -56,7 +120,8 @@ sched_get_priority_max(int policy) { if (policy < SCHED_MIN || policy > SCHED_MAX) { - return EINVAL; + errno = EINVAL; + return -1; } #if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) diff --git a/sched_get_priority_min.c b/sched_get_priority_min.c index 013c233..5c88137 100644 --- a/sched_get_priority_min.c +++ b/sched_get_priority_min.c @@ -48,6 +48,71 @@ * * sched_get_priority_min() returns 5 * sched_get_priority_max() returns 1 + * + * The following table shows the base priority levels for combinations + * of priority class and priority value in Win32. + * + * Process Priority Class Thread Priority Level + * ----------------------------------------------------------------- + * 1 IDLE_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 HIGH_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 2 IDLE_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 3 IDLE_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 4 IDLE_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 4 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 5 IDLE_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 5 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 5 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 6 IDLE_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 6 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 6 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 7 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 7 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 7 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 8 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 8 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 8 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 8 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 9 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 9 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 9 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 10 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 10 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 11 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 11 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 11 HIGH_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 12 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 12 HIGH_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 13 HIGH_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 14 HIGH_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 IDLE_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 16 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 17 REALTIME_PRIORITY_CLASS -7 + * 18 REALTIME_PRIORITY_CLASS -6 + * 19 REALTIME_PRIORITY_CLASS -5 + * 20 REALTIME_PRIORITY_CLASS -4 + * 21 REALTIME_PRIORITY_CLASS -3 + * 22 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 23 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 24 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 25 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 26 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 27 REALTIME_PRIORITY_CLASS 3 + * 28 REALTIME_PRIORITY_CLASS 4 + * 29 REALTIME_PRIORITY_CLASS 5 + * 30 REALTIME_PRIORITY_CLASS 6 + * 31 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * + * Windows NT: Values -7, -6, -5, -4, -3, 3, 4, 5, and 6 are not supported. + * */ @@ -56,7 +121,8 @@ sched_get_priority_min(int policy) { if (policy < SCHED_MIN || policy > SCHED_MAX) { - return EINVAL; + errno = EINVAL; + return -1; } #if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) diff --git a/tests/ChangeLog b/tests/ChangeLog index 2107c84..667747f 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,9 +1,28 @@ +2003-09-18 Ross Johnson + + * benchtest.h: Move old mutex code into benchlib.c. + * benchlib.c: New statically linked module to ensure that + bench apps don't inline the code and therefore have an unfair + advantage over the pthreads lib routines. Made little or no + difference. + * benchtest1.c: Minor change to avoid compiler warnings. + * benchtest5.c: Likewise. + * benchtest2.c: Fix misinformation in output report. + * README.BENCH: Add comments on results. + +2003-09-14 Ross Johnson + + * priority1.c: Reworked to comply with modified priority + management and provide additional output. + * priority2.c: Likewise. + * inherit1.c: Likewise. + 2003-09-03 Ross Johnson - * exit4.c: New test. - * exit5.c: New test. - * cancel7.c: New test. - * cancel8.c: New test. + * exit4.c: New test. + * exit5.c: New test. + * cancel7.c: New test. + * cancel8.c: New test. 2003-08-13 Ross Johnson diff --git a/tests/GNUmakefile b/tests/GNUmakefile index a308227..7ed1c85 100644 --- a/tests/GNUmakefile +++ b/tests/GNUmakefile @@ -47,6 +47,7 @@ MAKE = make # Mingw32 # XXCFLAGS = +XXLIBS = CFLAGS = -O3 -UNDEBUG -Wall $(XXCFLAGS) #CFLAGS = -g -O0 -UNDEBUG -Wall $(XXCFLAGS) BUILD_DIR = .. @@ -62,7 +63,7 @@ COPYFILES = $(HDR) $(LIB) $(DLL) # If a test case returns a non-zero exit code to the shell, make will # stop. -TESTS = loadfree \ +TESTS = sizes loadfree \ semaphore1 semaphore2 self1 mutex5 mutex1 mutex1e mutex1n mutex1r \ condvar1 condvar1_1 condvar1_2 condvar2 condvar2_1 exit1 \ create1 create2 reuse1 reuse2 equal1 \ @@ -115,10 +116,10 @@ GCX: $(MAKE) GCX=GC CC=g++ XXCFLAGS="-mthreads -D__CLEANUP_C" all-pass GC-bench: - $(MAKE) GCX=GC CC=gcc XXCFLAGS="-D__CLEANUP_C" all-bench + $(MAKE) GCX=GC CC=gcc XXCFLAGS="-D__CLEANUP_C" XXLIBS="benchlib.o" all-bench GCE-bench: - $(MAKE) GCX=GCE CC=g++ XXCFLAGS="-mthreads -D__CLEANUP_CXX" all-bench + $(MAKE) GCX=GCE CC=g++ XXCFLAGS="-mthreads -D__CLEANUP_CXX" XXLIBS="benchlib." all-bench all-pass: $(PASSES) @ $(ECHO) ALL TESTS PASSED! Congratulations! @@ -183,7 +184,7 @@ exit3.pass: create1.pass exit4.pass: exit5.pass: exit4.pass kill1.pass eyal1.pass: tsd1.pass -inherit1.pass: join1.pass +inherit1.pass: join1.pass priority1.pass join0.pass: create1.pass join1.pass: create1.pass join2.pass: create1.pass @@ -211,7 +212,7 @@ mutex8e.pass: mutex7e.pass mutex8r.pass: mutex7r.pass once1.pass: create1.pass priority1.pass: join1.pass -priority2.pass: priority1.pass +priority2.pass: priority1.pass barrier3.pass reuse1.pass: create2.pass reuse2.pass: reuse1.pass rwlock1.pass: condvar6.pass @@ -231,6 +232,7 @@ self1.pass: self2.pass: create1.pass semaphore1.pass: semaphore2.pass: +sizes.pass: spin1.pass: spin2.pass: spin1.pass spin3.pass: spin2.pass @@ -246,7 +248,7 @@ valid2.pass: valid1.pass @ $(ECHO) Passed @ $(TOUCH) $@ -%.bench: %.exe $(LIB) $(DLL) $(HDR) +%.bench: $(LIB) $(DLL) $(HDR) $(XXLIBS) %.exe @ $(ECHO) Running $* $* @ $(ECHO) Done @@ -254,8 +256,8 @@ valid2.pass: valid1.pass %.exe: %.c @ $(ECHO) Compiling $@ - @ $(ECHO) $(CC) $(CFLAGS) -o $@ $^ $(INCLUDES) -L. -lpthread$(GCX) - @ $(CC) $(CFLAGS) -o $@ $^ $(INCLUDES) -L. -lpthread$(GCX) -lsupc++ + @ $(ECHO) $(CC) $(CFLAGS) -o $@ $^ $(INCLUDES) -L. -lpthread$(GCX) -lsupc++ $(XXLIBS) + @ $(CC) $(CFLAGS) -o $@ $^ $(INCLUDES) -L. -lpthread$(GCX) -lsupc++ $(XXLIBS) %.pre: %.c @ $(CC) -E $(CFLAGS) -o $@ $^ $(INCLUDES) @@ -270,6 +272,11 @@ $(COPYFILES): pthread.dll: @ $(CP) $(DLL) $@ +benchlib.o: benchlib.c + @ $(ECHO) Compiling $@ + @ $(ECHO) $(CC) -c $(CFLAGS) $^ $(INCLUDES) + @ $(CC) -c $(CFLAGS) $^ $(INCLUDES) + clean: - $(RM) *.dll - $(RM) *.lib @@ -279,6 +286,7 @@ clean: - $(RM) *.a - $(RM) *.e - $(RM) *.i + - $(RM) *.o - $(RM) *.obj - $(RM) *.pdb - $(RM) *.exe diff --git a/tests/Makefile b/tests/Makefile index 94c593f..210b8a1 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -42,6 +42,8 @@ CPHDR = pthread.h semaphore.h sched.h OPTIM = /O2 /Ob0 +XXLIBS = + # C++ Exceptions VCEFLAGS = /GX /TP /DPtW32NoCatchWarn /D__CLEANUP_CXX VCELIB = pthreadVCE.lib @@ -70,7 +72,7 @@ EHFLAGS = # If a test case returns a non-zero exit code to the shell, make will # stop. -PASSES= loadfree.pass \ +PASSES= sizes.pass loadfree.pass \ semaphore1.pass semaphore2.pass self1.pass mutex5.pass \ mutex1.pass mutex1n.pass mutex1e.pass mutex1r.pass mutex2.pass mutex3.pass \ condvar1.pass condvar1_1.pass condvar1_2.pass condvar2.pass condvar2_1.pass \ @@ -93,7 +95,7 @@ PASSES= loadfree.pass \ rwlock2_t.pass rwlock3_t.pass rwlock4_t.pass rwlock5_t.pass rwlock6_t.pass rwlock6_t2.pass \ context1.pass \ cancel3.pass cancel4.pass cancel5.pass cancel6a.pass cancel6d.pass \ - cancel7 cancel8 \ + cancel7 cancel8 \ cleanup0.pass cleanup1.pass cleanup2.pass cleanup3.pass \ priority1.pass priority2.pass inherit1.pass \ spin1.pass spin2.pass spin3.pass spin4.pass \ @@ -124,7 +126,7 @@ all: tests: $(CPLIB) $(CPDLL) $(CPHDR) $(PASSES) @ $(ECHO) ALL TESTS PASSED! Congratulations! -benchtests: $(CPLIB) $(CPDLL) $(CPHDR) $(BENCHRESULTS) +benchtests: $(CPLIB) $(CPDLL) $(CPHDR) $(XXLIBS) $(BENCHRESULTS) @ $(ECHO) ALL BENCH TESTS DONE. $(PASSES): $*.exe @@ -152,20 +154,24 @@ VCX: @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCXFLAGS)" tests VCE-bench: - @ nmake TEST="$@" CPLIB="$(VCELIB)" CPDLL="$(VCEDLL)" EHFLAGS="$(VCEFLAGS)" benchtests + @ nmake TEST="$@" CPLIB="$(VCELIB)" CPDLL="$(VCEDLL)" EHFLAGS="$(VCEFLAGS)" XXLIBS="benchlib.o" benchtests VSE-bench: - @ nmake TEST="$@" CPLIB="$(VSELIB)" CPDLL="$(VSEDLL)" EHFLAGS="$(VSEFLAGS)" benchtests + @ nmake TEST="$@" CPLIB="$(VSELIB)" CPDLL="$(VSEDLL)" EHFLAGS="$(VSEFLAGS)" XXLIBS="benchlib.o" benchtests VC-bench: - @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" benchtests + @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" XXLIBS="benchlib.o" benchtests VCX-bench: - @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCXFLAGS)" benchtests + @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCXFLAGS)" XXLIBS="benchlib.o" benchtests .c.exe: - @ $(ECHO) $(CC) $(EHFLAGS) $(CFLAGS) $(INCLUDES) $< /Fe$@ /link $(LFLAGS) $(CPLIB) - @ $(CC) $(EHFLAGS) $(CFLAGS) $(INCLUDES) $< /Fe$@ /link $(LFLAGS) $(CPLIB) + @ $(ECHO) $(CC) $(EHFLAGS) $(CFLAGS) $(INCLUDES) $< /Fe$@ /link $(LFLAGS) $(CPLIB) $(XXLIBS) + @ $(CC) $(EHFLAGS) $(CFLAGS) $(INCLUDES) $< /Fe$@ /link $(LFLAGS) $(CPLIB) $(XXLIBS) + +.c.o: + @ $(ECHO) $(CC) $(EHFLAGS) /c $(CFLAGS) $(INCLUDES) $< /Fo$@ + @ $(CC) $(EHFLAGS) $(CFLAGS) /c $(INCLUDES) $< /Fo$@ .c.i: @ $(CC) /P $(EHFLAGS) $(CFLAGS) $(INCLUDES) $< @@ -250,7 +256,7 @@ exit3.pass: create1.pass exit4.pass: exit5.pass: kill1.pass eyal1.pass: tsd1.pass -inherit1.pass: join1.pass +inherit1.pass: join1.pass priority1.pass join0.pass: create1.pass join1.pass: create1.pass join2.pass: create1.pass @@ -278,7 +284,7 @@ mutex8e.pass: mutex7e.pass mutex8r.pass: mutex7r.pass once1.pass: create1.pass priority1.pass: join1.pass -priority2.pass: priority1.pass +priority2.pass: priority1.pass barrier3.pass reuse1.pass: create2.pass reuse2.pass: reuse1.pass rwlock1.pass: condvar6.pass @@ -298,6 +304,7 @@ self1.pass: self2.pass: create1.pass semaphore1.pass: semaphore2.pass: +sizes.pass: spin1.pass: spin2.pass: spin1.pass spin3.pass: spin2.pass diff --git a/tests/README.benchtests b/tests/README.benchtests index 1d8e1e3..01051a2 100644 --- a/tests/README.benchtests +++ b/tests/README.benchtests @@ -1,66 +1,97 @@ - ------------- -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: - -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. - - -Mutex benchtests ----------------- - -benchtest1 - Lock plus unlock on an unlocked mutex. -benchtest2 - Lock plus unlock on a locked mutex. -benchtest3 - Trylock on a locked mutex. -benchtest4 - Trylock plus unlock on an unlocked mutex. - - -Each test times up to three alternate synchronisation -implementations as a reference, and then times each of -the four mutex types provided by the library. Each is -described below: - -Simple Critical Section -- uses a simple Win32 critical section. There is no -additional overhead for this case as there is in the -remaining cases. - -POSIX mutex implemented using a Critical Section -- The old implementation which uses runtime adaptation -depending on the Windows variant being run on. When -the pthreads DLL was run on WinNT or higher then -POSIX mutexes would use Win32 Critical Sections. - -POSIX mutex implemented using a Win32 Mutex -- The old implementation which uses runtime adaptation -depending on the Windows variant being run on. When -the pthreads DLL was run on Win9x then POSIX mutexes -would use Win32 Mutexes (because TryEnterCriticalSection -is not implemented on Win9x). - -PTHREAD_MUTEX_DEFAULT -PTHREAD_MUTEX_NORMAL -PTHREAD_MUTEX_ERRORCHECK -PTHREAD_MUTEX_RECURSIVE -- The current implementation supports these mutex types. -The underlying basis of POSIX mutexes is now the same -irrespective of the Windows variant. - - -In all benchtests, the operation is repeated a large -number of times and an average is calculated. Loop -overhead is measured and subtracted from all test times. + +------------ +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: + +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. + + +Mutex benchtests +---------------- + +benchtest1 - Lock plus unlock on an unlocked mutex. +benchtest2 - Lock plus unlock on a locked mutex. +benchtest3 - Trylock on a locked mutex. +benchtest4 - Trylock plus unlock on an unlocked mutex. + + +Each test times up to three alternate synchronisation +implementations as a reference, and then times each of +the four mutex types provided by the library. Each is +described below: + +Simple Critical Section +- uses a simple Win32 critical section. There is no +additional overhead for this case as there is in the +remaining cases. + +POSIX mutex implemented using a Critical Section +- The old implementation which uses runtime adaptation +depending on the Windows variant being run on. When +the pthreads DLL was run on WinNT or higher then +POSIX mutexes would use Win32 Critical Sections. + +POSIX mutex implemented using a Win32 Mutex +- The old implementation which uses runtime adaptation +depending on the Windows variant being run on. When +the pthreads DLL was run on Win9x then POSIX mutexes +would use Win32 Mutexes (because TryEnterCriticalSection +is not implemented on Win9x). + +PTHREAD_MUTEX_DEFAULT +PTHREAD_MUTEX_NORMAL +PTHREAD_MUTEX_ERRORCHECK +PTHREAD_MUTEX_RECURSIVE +- The current implementation supports these mutex types. +The underlying basis of POSIX mutexes is now the same +irrespective of the Windows variant, and should therefore +have consistent performance. + + +In all benchtests, the operation is repeated a large +number of times and an average is calculated. Loop +overhead is measured and subtracted from all test times. + +Comment on the results +---------------------- +The gain in performance for Win9x systems is enormous - up to +40 times faster for unlocked mutexes (2 times faster for locked +mutexes). + +Pthread_mutex_trylock also appears to be faster for locked mutexes. + +The price for the new consistency between WinNT and Win9x is +slower performance (up to twice as long) across a lock/unlock +sequence. It is difficult to get a good split timing for lock +and unlock operations, but by code inspection, it is the unlock +operation that is slowing the pair down in comparison with the +old-style CS mutexes, even for the fast PTHREAD_MUTEX_NORMAL mutex +type with no other waiting threads. However, comparitive +performance for operations on already locked mutexes is very close. + +When this is translated to real-world applications, the overall +camparitive performance should be almost identical on NT class +systems. That is, applications with heavy mutex contention should +have almost equal performance, while applications with only light +mutex contention should also have almost equal performance because +the most critical operation in this case is the lock operation. + +Overall, the newer pthreads-win32 mutex routines are only slower +(on NT class systems) where and when it is least critical. + +Thanks go to Thomas Pfaff for the current implementation of mutex +routines. diff --git a/tests/SIZES.GC b/tests/SIZES.GC new file mode 100755 index 0000000..ae09a84 --- /dev/null +++ b/tests/SIZES.GC @@ -0,0 +1,20 @@ +Sizes of pthreads-win32 structs +------------------------------- + pthread_t_ 124 + pthread_attr_t_ 28 + sem_t_ 4 + pthread_mutex_t_ 44 + pthread_mutexattr_t_ 8 + pthread_spinlock_t_ 8 + pthread_barrier_t_ 24 + pthread_barrierattr_t_ 4 + pthread_key_t_ 16 + pthread_cond_t_ 32 + pthread_condattr_t_ 4 + pthread_rwlock_t_ 28 + pthread_rwlockattr_t_ 4 + pthread_once_t_ 8 + ptw32_cleanup_t 12 + sched_param 4 +------------------------------- + diff --git a/tests/SIZES.GCE b/tests/SIZES.GCE new file mode 100755 index 0000000..f36d0d2 --- /dev/null +++ b/tests/SIZES.GCE @@ -0,0 +1,20 @@ +Sizes of pthreads-win32 structs +------------------------------- + pthread_t_ 60 + pthread_attr_t_ 28 + sem_t_ 4 + pthread_mutex_t_ 44 + pthread_mutexattr_t_ 8 + pthread_spinlock_t_ 8 + pthread_barrier_t_ 24 + pthread_barrierattr_t_ 4 + pthread_key_t_ 16 + pthread_cond_t_ 32 + pthread_condattr_t_ 4 + pthread_rwlock_t_ 28 + pthread_rwlockattr_t_ 4 + pthread_once_t_ 8 + ptw32_cleanup_t 12 + sched_param 4 +------------------------------- + diff --git a/tests/SIZES.VC b/tests/SIZES.VC new file mode 100755 index 0000000..ae09a84 --- /dev/null +++ b/tests/SIZES.VC @@ -0,0 +1,20 @@ +Sizes of pthreads-win32 structs +------------------------------- + pthread_t_ 124 + pthread_attr_t_ 28 + sem_t_ 4 + pthread_mutex_t_ 44 + pthread_mutexattr_t_ 8 + pthread_spinlock_t_ 8 + pthread_barrier_t_ 24 + pthread_barrierattr_t_ 4 + pthread_key_t_ 16 + pthread_cond_t_ 32 + pthread_condattr_t_ 4 + pthread_rwlock_t_ 28 + pthread_rwlockattr_t_ 4 + pthread_once_t_ 8 + ptw32_cleanup_t 12 + sched_param 4 +------------------------------- + diff --git a/tests/benchlib.c b/tests/benchlib.c new file mode 100644 index 0000000..78ec3c8 --- /dev/null +++ b/tests/benchlib.c @@ -0,0 +1,338 @@ +/* + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2003 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + */ + +#include "../config.h" + +#include "pthread.h" +#include "sched.h" +#include "semaphore.h" +#include +#include + +#ifdef __GNUC__ +#include +#endif + +#include "benchtest.h" + +int old_mutex_use = OLD_WIN32CS; + +BOOL (WINAPI *ptw32_try_enter_critical_section)(LPCRITICAL_SECTION) = NULL; +HINSTANCE ptw32_h_kernel32; + +int +old_mutex_init(old_mutex_t *mutex, const old_mutexattr_t *attr) +{ + int result = 0; + old_mutex_t mx; + + if (mutex == NULL) + { + return EINVAL; + } + + mx = (old_mutex_t) calloc(1, sizeof(*mx)); + + if (mx == NULL) + { + result = ENOMEM; + goto FAIL0; + } + + mx->mutex = 0; + + if (attr != NULL + && *attr != NULL + && (*attr)->pshared == PTHREAD_PROCESS_SHARED + ) + { + result = ENOSYS; + } + else + { + CRITICAL_SECTION cs; + + /* + * Load KERNEL32 and try to get address of TryEnterCriticalSection + */ + ptw32_h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL")); + ptw32_try_enter_critical_section = (BOOL (WINAPI *)(LPCRITICAL_SECTION)) + +#if defined(NEED_UNICODE_CONSTS) + GetProcAddress(ptw32_h_kernel32, + (const TCHAR *)TEXT("TryEnterCriticalSection")); +#else + GetProcAddress(ptw32_h_kernel32, + (LPCSTR) "TryEnterCriticalSection"); +#endif + + if (ptw32_try_enter_critical_section != NULL) + { + InitializeCriticalSection(&cs); + if ((*ptw32_try_enter_critical_section)(&cs)) + { + LeaveCriticalSection(&cs); + } + else + { + /* + * Not really supported (Win98?). + */ + ptw32_try_enter_critical_section = NULL; + } + DeleteCriticalSection(&cs); + } + + if (ptw32_try_enter_critical_section == NULL) + { + (void) FreeLibrary(ptw32_h_kernel32); + ptw32_h_kernel32 = 0; + } + + if (old_mutex_use == OLD_WIN32CS) + { + InitializeCriticalSection(&mx->cs); + } + else if (old_mutex_use == OLD_WIN32MUTEX) + { + mx->mutex = CreateMutex (NULL, + FALSE, + NULL); + + if (mx->mutex == 0) + { + result = EAGAIN; + } + } + else + { + result = EINVAL; + } + } + + if (result != 0 && mx != NULL) + { + free(mx); + mx = NULL; + } + +FAIL0: + *mutex = mx; + + return(result); +} + + +int +old_mutex_lock(old_mutex_t *mutex) +{ + int result = 0; + old_mutex_t mx; + + if (mutex == NULL || *mutex == NULL) + { + return EINVAL; + } + + if (*mutex == (old_mutex_t) PTW32_OBJECT_AUTO_INIT) + { + /* + * Don't use initialisers when benchtesting. + */ + result = EINVAL; + } + + mx = *mutex; + + if (result == 0) + { + if (mx->mutex == 0) + { + EnterCriticalSection(&mx->cs); + } + else + { + result = (WaitForSingleObject(mx->mutex, INFINITE) + == WAIT_OBJECT_0) + ? 0 + : EINVAL; + } + } + + return(result); +} + +int +old_mutex_unlock(old_mutex_t *mutex) +{ + int result = 0; + old_mutex_t mx; + + if (mutex == NULL || *mutex == NULL) + { + return EINVAL; + } + + mx = *mutex; + + if (mx != (old_mutex_t) PTW32_OBJECT_AUTO_INIT) + { + if (mx->mutex == 0) + { + LeaveCriticalSection(&mx->cs); + } + else + { + result = (ReleaseMutex (mx->mutex) ? 0 : EINVAL); + } + } + else + { + result = EINVAL; + } + + return(result); +} + + +int +old_mutex_trylock(old_mutex_t *mutex) +{ + int result = 0; + old_mutex_t mx; + + if (mutex == NULL || *mutex == NULL) + { + return EINVAL; + } + + if (*mutex == (old_mutex_t) PTW32_OBJECT_AUTO_INIT) + { + /* + * Don't use initialisers when benchtesting. + */ + result = EINVAL; + } + + mx = *mutex; + + if (result == 0) + { + if (mx->mutex == 0) + { + if (ptw32_try_enter_critical_section == NULL) + { + result = 0; + } + else if ((*ptw32_try_enter_critical_section)(&mx->cs) != TRUE) + { + result = EBUSY; + } + } + else + { + DWORD status; + + status = WaitForSingleObject (mx->mutex, 0); + + if (status != WAIT_OBJECT_0) + { + result = ((status == WAIT_TIMEOUT) + ? EBUSY + : EINVAL); + } + } + } + + return(result); +} + + +int +old_mutex_destroy(old_mutex_t *mutex) +{ + int result = 0; + old_mutex_t mx; + + if (mutex == NULL + || *mutex == NULL) + { + return EINVAL; + } + + if (*mutex != (old_mutex_t) PTW32_OBJECT_AUTO_INIT) + { + mx = *mutex; + + if ((result = old_mutex_trylock(&mx)) == 0) + { + *mutex = NULL; + + (void) old_mutex_unlock(&mx); + + if (mx->mutex == 0) + { + DeleteCriticalSection(&mx->cs); + } + else + { + result = (CloseHandle (mx->mutex) ? 0 : EINVAL); + } + + if (result == 0) + { + mx->mutex = 0; + free(mx); + } + else + { + *mutex = mx; + } + } + } + else + { + result = EINVAL; + } + + if (ptw32_try_enter_critical_section != NULL) + { + (void) FreeLibrary(ptw32_h_kernel32); + ptw32_h_kernel32 = 0; + } + + return(result); +} + +/****************************************************************************************/ diff --git a/tests/benchtest.h b/tests/benchtest.h index c04e62e..2401622 100644 --- a/tests/benchtest.h +++ b/tests/benchtest.h @@ -39,7 +39,7 @@ enum { OLD_WIN32MUTEX }; -static int old_mutex_use = OLD_WIN32CS; +extern int old_mutex_use; struct old_mutex_t_ { HANDLE mutex; @@ -54,293 +54,14 @@ struct old_mutexattr_t_ { typedef struct old_mutexattr_t_ * old_mutexattr_t; -static BOOL (WINAPI *ptw32_try_enter_critical_section)(LPCRITICAL_SECTION) = NULL; -static HINSTANCE ptw32_h_kernel32; +extern BOOL (WINAPI *ptw32_try_enter_critical_section)(LPCRITICAL_SECTION); +extern HINSTANCE ptw32_h_kernel32; #define PTW32_OBJECT_AUTO_INIT ((void *) -1) -static int -old_mutex_init(old_mutex_t *mutex, const old_mutexattr_t *attr) -{ - int result = 0; - old_mutex_t mx; - - if (mutex == NULL) - { - return EINVAL; - } - - mx = (old_mutex_t) calloc(1, sizeof(*mx)); - - if (mx == NULL) - { - result = ENOMEM; - goto FAIL0; - } - - mx->mutex = 0; - - if (attr != NULL - && *attr != NULL - && (*attr)->pshared == PTHREAD_PROCESS_SHARED - ) - { - result = ENOSYS; - } - else - { - CRITICAL_SECTION cs; - - /* - * Load KERNEL32 and try to get address of TryEnterCriticalSection - */ - ptw32_h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL")); - ptw32_try_enter_critical_section = (BOOL (WINAPI *)(LPCRITICAL_SECTION)) - -#if defined(NEED_UNICODE_CONSTS) - GetProcAddress(ptw32_h_kernel32, - (const TCHAR *)TEXT("TryEnterCriticalSection")); -#else - GetProcAddress(ptw32_h_kernel32, - (LPCSTR) "TryEnterCriticalSection"); -#endif - - if (ptw32_try_enter_critical_section != NULL) - { - InitializeCriticalSection(&cs); - if ((*ptw32_try_enter_critical_section)(&cs)) - { - LeaveCriticalSection(&cs); - } - else - { - /* - * Not really supported (Win98?). - */ - ptw32_try_enter_critical_section = NULL; - } - DeleteCriticalSection(&cs); - } - - if (ptw32_try_enter_critical_section == NULL) - { - (void) FreeLibrary(ptw32_h_kernel32); - ptw32_h_kernel32 = 0; - } - - if (old_mutex_use == OLD_WIN32CS) - { - InitializeCriticalSection(&mx->cs); - } - else if (old_mutex_use == OLD_WIN32MUTEX) - { - mx->mutex = CreateMutex (NULL, - FALSE, - NULL); - - if (mx->mutex == 0) - { - result = EAGAIN; - } - } - else - { - result = EINVAL; - } - } - - if (result != 0 && mx != NULL) - { - free(mx); - mx = NULL; - } - -FAIL0: - *mutex = mx; - - return(result); -} - - -static int -old_mutex_lock(old_mutex_t *mutex) -{ - int result = 0; - old_mutex_t mx; - - if (mutex == NULL || *mutex == NULL) - { - return EINVAL; - } - - if (*mutex == (old_mutex_t) PTW32_OBJECT_AUTO_INIT) - { - /* - * Don't use initialisers when benchtesting. - */ - result = EINVAL; - } - - mx = *mutex; - - if (result == 0) - { - if (mx->mutex == 0) - { - EnterCriticalSection(&mx->cs); - } - else - { - result = (WaitForSingleObject(mx->mutex, INFINITE) - == WAIT_OBJECT_0) - ? 0 - : EINVAL; - } - } - - return(result); -} - -static int -old_mutex_unlock(old_mutex_t *mutex) -{ - int result = 0; - old_mutex_t mx; - - if (mutex == NULL || *mutex == NULL) - { - return EINVAL; - } - - mx = *mutex; - - if (mx != (old_mutex_t) PTW32_OBJECT_AUTO_INIT) - { - if (mx->mutex == 0) - { - LeaveCriticalSection(&mx->cs); - } - else - { - result = (ReleaseMutex (mx->mutex) ? 0 : EINVAL); - } - } - else - { - result = EINVAL; - } - - return(result); -} - - -static int -old_mutex_trylock(old_mutex_t *mutex) -{ - int result = 0; - old_mutex_t mx; - - if (mutex == NULL || *mutex == NULL) - { - return EINVAL; - } - - if (*mutex == (old_mutex_t) PTW32_OBJECT_AUTO_INIT) - { - /* - * Don't use initialisers when benchtesting. - */ - result = EINVAL; - } - - mx = *mutex; - - if (result == 0) - { - if (mx->mutex == 0) - { - if (ptw32_try_enter_critical_section == NULL) - { - result = 0; - } - else if ((*ptw32_try_enter_critical_section)(&mx->cs) != TRUE) - { - result = EBUSY; - } - } - else - { - DWORD status; - - status = WaitForSingleObject (mx->mutex, 0); - - if (status != WAIT_OBJECT_0) - { - result = ((status == WAIT_TIMEOUT) - ? EBUSY - : EINVAL); - } - } - } - - return(result); -} - - -static int -old_mutex_destroy(old_mutex_t *mutex) -{ - int result = 0; - old_mutex_t mx; - - if (mutex == NULL - || *mutex == NULL) - { - return EINVAL; - } - - if (*mutex != (old_mutex_t) PTW32_OBJECT_AUTO_INIT) - { - mx = *mutex; - - if ((result = old_mutex_trylock(&mx)) == 0) - { - *mutex = NULL; - - (void) old_mutex_unlock(&mx); - - if (mx->mutex == 0) - { - DeleteCriticalSection(&mx->cs); - } - else - { - result = (CloseHandle (mx->mutex) ? 0 : EINVAL); - } - - if (result == 0) - { - mx->mutex = 0; - free(mx); - } - else - { - *mutex = mx; - } - } - } - else - { - result = EINVAL; - } - - if (ptw32_try_enter_critical_section != NULL) - { - (void) FreeLibrary(ptw32_h_kernel32); - ptw32_h_kernel32 = 0; - } - - return(result); -} - +int old_mutex_init(old_mutex_t *mutex, const old_mutexattr_t *attr); +int old_mutex_lock(old_mutex_t *mutex); +int old_mutex_unlock(old_mutex_t *mutex); +int old_mutex_trylock(old_mutex_t *mutex); +int old_mutex_destroy(old_mutex_t *mutex); /****************************************************************************************/ diff --git a/tests/benchtest1.c b/tests/benchtest1.c index ed127ba..1a553dc 100644 --- a/tests/benchtest1.c +++ b/tests/benchtest1.c @@ -57,6 +57,8 @@ struct _timeb currSysTimeStart; struct _timeb currSysTimeStop; long durationMilliSecs; long overHeadMilliSecs = 0; +int one = 1; +int zero = 0; #define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.time*1000+_TStop.millitm) \ - (_TStart.time*1000+_TStart.millitm)) @@ -81,8 +83,8 @@ runTest (char * testNameString, int mType) assert(pthread_mutex_init(&mx, &ma) == 0); TESTSTART - assert(pthread_mutex_lock(&mx) == 0); - assert(pthread_mutex_unlock(&mx) == 0); + assert(pthread_mutex_lock(&mx) == zero); + assert(pthread_mutex_unlock(&mx) == zero); TESTSTOP assert(pthread_mutex_destroy(&mx) == 0); @@ -101,7 +103,6 @@ main (int argc, char *argv[]) { CRITICAL_SECTION cs; old_mutex_t ox; - pthread_mutexattr_init(&ma); printf( "=============================================================================\n"); @@ -118,8 +119,8 @@ main (int argc, char *argv[]) */ TESTSTART - assert(1 == 1); - assert(1 == 1); + assert(1 == one); + assert(1 == one); TESTSTOP durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; @@ -129,8 +130,8 @@ main (int argc, char *argv[]) InitializeCriticalSection(&cs); TESTSTART - assert((EnterCriticalSection(&cs), 1) == 1); - assert((LeaveCriticalSection(&cs), 1) == 1); + assert((EnterCriticalSection(&cs), 1) == one); + assert((LeaveCriticalSection(&cs), 1) == one); TESTSTOP DeleteCriticalSection(&cs); @@ -147,8 +148,8 @@ main (int argc, char *argv[]) assert(old_mutex_init(&ox, NULL) == 0); TESTSTART - assert(old_mutex_lock(&ox) == 0); - assert(old_mutex_unlock(&ox) == 0); + assert(old_mutex_lock(&ox) == zero); + assert(old_mutex_unlock(&ox) == zero); TESTSTOP assert(old_mutex_destroy(&ox) == 0); @@ -165,8 +166,8 @@ main (int argc, char *argv[]) assert(old_mutex_init(&ox, NULL) == 0); TESTSTART - assert(old_mutex_lock(&ox) == 0); - assert(old_mutex_unlock(&ox) == 0); + assert(old_mutex_lock(&ox) == zero); + assert(old_mutex_unlock(&ox) == zero); TESTSTOP assert(old_mutex_destroy(&ox) == 0); diff --git a/tests/benchtest2.c b/tests/benchtest2.c index b0ac7e4..7caf7c5 100644 --- a/tests/benchtest2.c +++ b/tests/benchtest2.c @@ -179,7 +179,7 @@ main (int argc, char *argv[]) assert(pthread_mutexattr_init(&ma) == 0); printf( "=============================================================================\n"); - printf( "\nLock plus unlock on an unlocked mutex.\n"); + printf( "\nLock plus unlock on a locked mutex.\n"); printf("%ld iterations, four locks/unlocks per iteration.\n\n", ITERATIONS); printf( "%-45s %15s %15s\n", diff --git a/tests/benchtest5.c b/tests/benchtest5.c index 11ad444..122fcb4 100644 --- a/tests/benchtest5.c +++ b/tests/benchtest5.c @@ -56,6 +56,8 @@ struct _timeb currSysTimeStart; struct _timeb currSysTimeStop; long durationMilliSecs; long overHeadMilliSecs = 0; +int one = 1; +int zero = 0; #define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.time*1000+_TStop.millitm) \ - (_TStart.time*1000+_TStart.millitm)) @@ -100,7 +102,7 @@ main (int argc, char *argv[]) */ TESTSTART - assert(1 == 1); + assert(1 == one); TESTSTOP durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; @@ -112,7 +114,7 @@ main (int argc, char *argv[]) */ assert(sem_init(&sema, 0, 0) == 0); TESTSTART - assert(sem_post(&sema) == 0); + assert(sem_post(&sema) == zero); TESTSTOP assert(sem_destroy(&sema) == 0); @@ -121,7 +123,7 @@ main (int argc, char *argv[]) assert(sem_init(&sema, 0, ITERATIONS) == 0); TESTSTART - assert(sem_wait(&sema) == 0); + assert(sem_wait(&sema) == zero); TESTSTOP assert(sem_destroy(&sema) == 0); @@ -133,8 +135,8 @@ main (int argc, char *argv[]) */ TESTSTART - assert(1 == 1); - assert(1 == 1); + assert(1 == one); + assert(1 == one); TESTSTOP durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; @@ -146,8 +148,8 @@ main (int argc, char *argv[]) */ assert(sem_init(&sema, 0, 0) == 0); TESTSTART - assert(sem_post(&sema) == 0); - assert(sem_wait(&sema) == 0); + assert(sem_post(&sema) == zero); + assert(sem_wait(&sema) == zero); TESTSTOP assert(sem_destroy(&sema) == 0); @@ -156,8 +158,8 @@ main (int argc, char *argv[]) assert(sem_init(&sema, 0, 1) == 0); TESTSTART - assert(sem_wait(&sema) == 0); - assert(sem_post(&sema) == 0); + assert(sem_wait(&sema) == zero); + assert(sem_post(&sema) == zero); TESTSTOP assert(sem_destroy(&sema) == 0); diff --git a/tests/inherit1.c b/tests/inherit1.c index 364aa74..288919c 100644 --- a/tests/inherit1.c +++ b/tests/inherit1.c @@ -97,21 +97,22 @@ void * getValidPriorities(void * arg) { int prioSet; - pthread_t threadID = pthread_self(); - HANDLE threadH = pthread_getw32threadhandle_np(threadID); + pthread_t thread = pthread_self(); + HANDLE threadH = pthread_getw32threadhandle_np(thread); + struct sched_param param; for (prioSet = minPrio; prioSet <= maxPrio; prioSet++) { - /* + /* * If prioSet is invalid then the threads priority is unchanged * from the previous value. Make the previous value a known * one so that we can check later. */ - SetThreadPriority(threadH, PTW32TEST_THREAD_INIT_PRIO); - SetThreadPriority(threadH, prioSet); - validPriorities[prioSet+(PTW32TEST_MAXPRIORITIES/2)] = GetThreadPriority(threadH); + param.sched_priority = prioSet; + assert(pthread_setschedparam(thread, SCHED_OTHER, ¶m) == 0); + validPriorities[prioSet+(PTW32TEST_MAXPRIORITIES/2)] = GetThreadPriority(threadH); } return (void *) 0; @@ -155,7 +156,9 @@ main() assert(pthread_setschedparam(mainThread, SCHED_OTHER, &mainParam) == 0); assert(pthread_getschedparam(mainThread, &policy, &mainParam) == 0); assert(policy == SCHED_OTHER); - assert(mainParam.sched_priority == + /* Priority returned below should be the level set by pthread_setschedparam(). */ + assert(mainParam.sched_priority == prio); + assert(GetThreadPriority(threadH) == validPriorities[prio+(PTW32TEST_MAXPRIORITIES/2)]); for (param.sched_priority = prio; diff --git a/tests/priority1.c b/tests/priority1.c index 48af6f7..1dc6ea7 100644 --- a/tests/priority1.c +++ b/tests/priority1.c @@ -101,6 +101,9 @@ getValidPriorities(void * arg) pthread_t threadID = pthread_self(); HANDLE threadH = pthread_getw32threadhandle_np(threadID); + printf("Using GetThreadPriority\n"); + printf("%10s %10s\n", "Set value", "Get value"); + for (prioSet = minPrio; prioSet <= maxPrio; prioSet++) @@ -110,9 +113,13 @@ getValidPriorities(void * arg) * from the previous value. Make the previous value a known * one so that we can check later. */ - SetThreadPriority(threadH, PTW32TEST_THREAD_INIT_PRIO); + if (prioSet < 0) + SetThreadPriority(threadH, THREAD_PRIORITY_LOWEST); + else + SetThreadPriority(threadH, THREAD_PRIORITY_HIGHEST); SetThreadPriority(threadH, prioSet); validPriorities[prioSet+(PTW32TEST_MAXPRIORITIES/2)] = GetThreadPriority(threadH); + printf("%10d %10d\n", prioSet, validPriorities[prioSet+(PTW32TEST_MAXPRIORITIES/2)]); } return (void *) 0; @@ -140,15 +147,23 @@ main() SetThreadPriority(pthread_getw32threadhandle_np(pthread_self()), PTW32TEST_THREAD_INIT_PRIO); + printf("Using pthread_getschedparam\n"); + printf("%10s %10s\n", "Set value", "Get value"); + for (param.sched_priority = minPrio; param.sched_priority <= maxPrio; param.sched_priority++) { assert(pthread_attr_setschedparam(&attr, ¶m) == 0); assert(pthread_create(&t, &attr, func, (void *) &attr) == 0); + + assert(GetThreadPriority(pthread_getw32threadhandle_np(t)) + == validPriorities[param.sched_priority+(PTW32TEST_MAXPRIORITIES/2)]); + assert(pthread_join(t, &result) == 0); - assert((int) result == - validPriorities[param.sched_priority+(PTW32TEST_MAXPRIORITIES/2)]); + + assert(param.sched_priority == (int) result); + printf("%10d %10d\n", param.sched_priority, (int) result); } return 0; diff --git a/tests/priority2.c b/tests/priority2.c index 54fd3a0..fc19ed5 100644 --- a/tests/priority2.c +++ b/tests/priority2.c @@ -81,27 +81,31 @@ enum { int minPrio; int maxPrio; int validPriorities[PTW32TEST_MAXPRIORITIES]; -pthread_mutex_t startMx = PTHREAD_MUTEX_INITIALIZER; +pthread_barrier_t startBarrier, endBarrier; void * func(void * arg) { int policy; + int result; struct sched_param param; - assert(pthread_mutex_lock(&startMx) == 0); + result = pthread_barrier_wait(&startBarrier); + assert(result == 0 || result == PTHREAD_BARRIER_SERIAL_THREAD); assert(pthread_getschedparam(pthread_self(), &policy, ¶m) == 0); - assert(pthread_mutex_unlock(&startMx) == 0); assert(policy == SCHED_OTHER); + result = pthread_barrier_wait(&endBarrier); + assert(result == 0 || result == PTHREAD_BARRIER_SERIAL_THREAD); return (void *) param.sched_priority; } - + void * getValidPriorities(void * arg) { int prioSet; - pthread_t threadID = pthread_self(); - HANDLE threadH = pthread_getw32threadhandle_np(threadID); + pthread_t thread = pthread_self(); + HANDLE threadH = pthread_getw32threadhandle_np(thread); + struct sched_param param; for (prioSet = minPrio; prioSet <= maxPrio; @@ -112,8 +116,8 @@ getValidPriorities(void * arg) * from the previous value. Make the previous value a known * one so that we can check later. */ - SetThreadPriority(threadH, PTW32TEST_THREAD_INIT_PRIO); - SetThreadPriority(threadH, prioSet); + param.sched_priority = prioSet; + assert(pthread_setschedparam(thread, SCHED_OTHER, ¶m) == 0); validPriorities[prioSet+(PTW32TEST_MAXPRIORITIES/2)] = GetThreadPriority(threadH); } @@ -126,6 +130,7 @@ main() { pthread_t t; void * result = NULL; + int result2; struct sched_param param; assert((maxPrio = sched_get_priority_max(SCHED_OTHER)) != -1); @@ -134,6 +139,9 @@ main() assert(pthread_create(&t, NULL, getValidPriorities, NULL) == 0); assert(pthread_join(t, &result) == 0); + assert(pthread_barrier_init(&startBarrier, NULL, 2) == 0); + assert(pthread_barrier_init(&endBarrier, NULL, 2) == 0); + /* Set the thread's priority to a known initial value. * If the new priority is invalid then the threads priority * is unchanged from the previous value. @@ -145,13 +153,16 @@ main() param.sched_priority <= maxPrio; param.sched_priority++) { - assert(pthread_mutex_lock(&startMx) == 0); assert(pthread_create(&t, NULL, func, NULL) == 0); assert(pthread_setschedparam(t, SCHED_OTHER, ¶m) == 0); - assert(pthread_mutex_unlock(&startMx) == 0); - pthread_join(t, &result); - assert((int) result == + result2 = pthread_barrier_wait(&startBarrier); + assert(result2 == 0 || result2 == PTHREAD_BARRIER_SERIAL_THREAD); + result2 = pthread_barrier_wait(&endBarrier); + assert(result2 == 0 || result2 == PTHREAD_BARRIER_SERIAL_THREAD); + assert(GetThreadPriority(pthread_getw32threadhandle_np(t)) == validPriorities[param.sched_priority+(PTW32TEST_MAXPRIORITIES/2)]); + pthread_join(t, &result); + assert(param.sched_priority == (int)result); } return 0; diff --git a/tests/sizes.c b/tests/sizes.c new file mode 100644 index 0000000..709c610 --- /dev/null +++ b/tests/sizes.c @@ -0,0 +1,28 @@ +#include "test.h" +#include "../implement.h" + +int +main() +{ + printf("Sizes of pthreads-win32 structs\n"); + printf("-------------------------------\n"); + printf("%30s %4d\n", "pthread_t_", sizeof(struct pthread_t_)); + printf("%30s %4d\n", "pthread_attr_t_", sizeof(struct pthread_attr_t_)); + printf("%30s %4d\n", "sem_t_", sizeof(struct sem_t_)); + printf("%30s %4d\n", "pthread_mutex_t_", sizeof(struct pthread_mutex_t_)); + printf("%30s %4d\n", "pthread_mutexattr_t_", sizeof(struct pthread_mutexattr_t_)); + printf("%30s %4d\n", "pthread_spinlock_t_", sizeof(struct pthread_spinlock_t_)); + printf("%30s %4d\n", "pthread_barrier_t_", sizeof(struct pthread_barrier_t_)); + printf("%30s %4d\n", "pthread_barrierattr_t_", sizeof(struct pthread_barrierattr_t_)); + printf("%30s %4d\n", "pthread_key_t_", sizeof(struct pthread_key_t_)); + printf("%30s %4d\n", "pthread_cond_t_", sizeof(struct pthread_cond_t_)); + printf("%30s %4d\n", "pthread_condattr_t_", sizeof(struct pthread_condattr_t_)); + printf("%30s %4d\n", "pthread_rwlock_t_", sizeof(struct pthread_rwlock_t_)); + printf("%30s %4d\n", "pthread_rwlockattr_t_", sizeof(struct pthread_rwlockattr_t_)); + printf("%30s %4d\n", "pthread_once_t_", sizeof(struct pthread_once_t_)); + printf("%30s %4d\n", "ptw32_cleanup_t", sizeof(struct ptw32_cleanup_t)); + printf("%30s %4d\n", "sched_param", sizeof(struct sched_param)); + printf("-------------------------------\n"); + + return 0; +} -- cgit v1.2.3