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. --- 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 ++++ 16 files changed, 663 insertions(+), 419 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 (limited to 'tests') 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