diff --git a/.gitignore b/.gitignore index 0fa70b6..7d7555e 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ tests/benchlib.o tests/SIZES.* tests/*.log /.project +build +PTHREADS-BUILT +.vscode \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..c4e22c7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,108 @@ +language: shell + +os: windows + +env: + - BUILD_TYPE=Debug VS2017=amd64 TESTING=OFF + - BUILD_TYPE=Release VS2017=amd64 TESTING=OFF + - BUILD_TYPE=MinSizeRel VS2017=amd64 TESTING=OFF + - BUILD_TYPE=MinSizeRel VS2017=amd64 TESTING=OFF + + - BUILD_TYPE=Debug VS2017=amd64_x86 TESTING=OFF + - BUILD_TYPE=Release VS2017=amd64_x86 TESTING=OFF + - BUILD_TYPE=MinSizeRel VS2017=amd64_x86 TESTING=OFF + - BUILD_TYPE=MinSizeRel VS2017=amd64_x86 TESTING=OFF + + #- BUILD_TYPE=Debug VS2017=amd64_arm TESTING=OFF + #- BUILD_TYPE=Release VS2017=amd64_arm TESTING=OFF + #- BUILD_TYPE=MinSizeRel VS2017=amd64_arm TESTING=OFF + #- BUILD_TYPE=MinSizeRel VS2017=amd64_arm TESTING=OFF + + #- BUILD_TYPE=Debug VS2017=amd64_arm64 TESTING=OFF + #- BUILD_TYPE=Release VS2017=amd64_arm64 TESTING=OFF + #- BUILD_TYPE=MinSizeRel VS2017=amd64_arm64 TESTING=OFF + #- BUILD_TYPE=MinSizeRel VS2017=amd64_arm64 TESTING=OFF + +#install: + #- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" + #- mkdir ${DEPS_DIR} && cd ${DEPS_DIR} && pwd + #- travis_retry wget --no-check-certificate https://cmake.org/files/v3.11/cmake-3.11.0-win64-x64.zip + #- echo "615dfb0813443c1ff56ae0e9d6dbfc61 *cmake-3.11.0-win64-x64.zip" > cmake_md5.txt + #- md5sum -c cmake_md5.txt + #- 7z x -y cmake-3.11.0-win64-x64.zip + #- PATH=${DEPS_DIR}/cmake-3.11.0-win64-x64:${DEPS_DIR}/cmake-3.11.0-win64-x64/bin:$PATH + +before_script: + + # document the version + #- cmake --version + #- cmake --help + + # set enviromental variables + - ls "/c/Progra~2/Microsoft Visual Studio/2017/BuildTools/VC/Auxiliary/Build/" + #vcvars32.bat + #vcvars64.bat + #vcvarsall.bat + #vcvarsamd64_arm.bat + #vcvarsamd64_arm64.bat + #vcvarsamd64_x86.bat + #vcvarsx86_amd64.bat + #vcvarsx86_arm.bat + #vcvarsx86_arm64.bat + #- printenv + + #- msvcenv="__msvc.bat" + #- echo "@echo off" > "$msvcenv" + #- echo "call /c/Progra~2/Microsoft\ Visual\ Studio/2017/BuildTools/VC/Auxiliary/Build/vcvarsall.bat ${VS2017}" >> "$msvcenv" + #- echo "set" >> "$msvcenv" + #- cmd "/K $msvcenv" + # > "$msenv.tmp" + + #- cat "$msvcenv" + #- rm -f "$msvcenv" + + - printenv + + #- cat "$msenv.tmp" + + #- grep -e '^PATH=' "$msenv.tmp" | \ + #sed \ + #-e 's/\(.*\)=\(.*\)/export \1="\2:$PATH"/g' \ + #-e 's/\([a-zA-Z]\):[\\\/]/\/\1\//g' \ + #-e 's/\\/\//g' -e 's/;\//:\//g' + # > "$msenv" + #- grep -e '^(INCLUDE|LIB|LIBPATH)=' "$msenv.tmp" | sed -e 's/\(.*\)=\(.*\)/export \1="\2"/g' >> "$msenv" + #- rm "$msenv.tmp" + #- cat "$msenv" + #- source "$msenv" + + #- printenv + + - call "c:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars32.bat" ${VS2017} + #- cmd "/K C:\\Progra~2\\Microsoft\ Visual\ Studio\\2017\\BuildTools\\VC\\Auxiliary\\Build\\vcvarsall.bat ${VS2017}" + #- /c/Progra~2/Microsoft\ Visual\ Studio/2017/BuildTools/VC/Auxiliary/Build/vcvarsall.bat ${VS2017} > "$msenv.tmp" + #- cat "$msenv.tmp" + #- printenv + + # Visual Studio 2015 + #- ls "/c/Progra~2/Microsoft Visual Studio 14.0/VC/" + #- /c/Progra~2/Microsoft\ Visual\ Studio\ 14.0/VC/vcvarsall.bat amd64 + + # generate the build files + - cd ${TRAVIS_BUILD_DIR} && mkdir build && cd build + - cmake -G"NMake Makefiles" -DCMAKE_VERBOSE_MAKEFILE=FALSE -DCMAKE_BUILD_TYPE=${BUILD_TYPE} + #-DBUILD_NUMBER=${TRAVIS_BUILD_NUMBER} + #-DDIST_ROOT="${TRAVIS_BUILD_DIR}/build/dist" + #-DENABLE_TESTS=${TESTING} + #.. +script: + - cmake --build . --config ${BUILD_TYPE} --target install + +addons: + coverity_scan: + project: + name: “jwinarske/pthreads4w" + notification_email: joel.winarske@gmail.com + build_command_prepend: "mkdir build && cd build && cmake -DCMAKE_VERBOSE_MAKEFILE=TRUE -DDCMAKE_INSTALL_PREFIX=`pwd`/dist .." + build_command: "cmake --build . --target install" + branch_pattern: coverity_scan diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..4e794ff --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,155 @@ +cmake_minimum_required(VERSION 3.11) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "MinSizeRel" CACHE STRING "Choose the type of build, options are: Debug, Release, or MinSizeRel." FORCE) + message(STATUS "No build type specified, defaulting to MinSizeRel.") +endif() + +set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_SOURCE_DIR}/cmake") + +include (get_version) + +message(STATUS "Generator ......... ${CMAKE_GENERATOR}") +message(STATUS "Build Type ........ ${CMAKE_BUILD_TYPE}") +message(STATUS "Version ........... ${PTHREADS4W_VERSION}") + +project(pthreads4w VERSION ${PTHREADS4W_VERSION} LANGUAGES C) + +set(PTW32_VER ${PROJECT_VERSION_MAJOR}${EXTRAVERSION}) +set(CMAKE_DEBUG_POSTFIX d) + +# Uncomment this if config.h defines RETAIN_WSALASTERROR +#set(XLIBS wsock32.lib) + + +include_directories(.) + +################################# +# Target Arch # +################################# +include (target_arch) + +get_target_arch(TARGET_ARCH) + +if(${TARGET_ARCH} STREQUAL "ARM") + add_definitions(-D__PTW32_ARCHARM -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1) +elseif(${TARGET_ARCH} STREQUAL "ARM64") + add_definitions(-D__PTW32_ARCHARM64 -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1) +elseif(${TARGET_ARCH} STREQUAL "x86_64") + add_definitions(-D__PTW32_ARCHAMD64) +elseif(${TARGET_ARCH} STREQUAL "x86") + add_definitions(-D__PTW32_ARCHX86) +elseif(${TARGET_ARCH} STREQUAL "x64") + add_definitions(-D__PTW32_ARCHX64) +else() + MESSAGE(ERROR "\"${TARGET_ARCH}\" not supported in version.rc") +endif() +message(STATUS "Target ............ ${TARGET_ARCH}") + +if(MSVC) + message(STATUS "MSVC Version ...... ${MSVC_VERSION}") +endif() + +################################# +# Install Path # +################################# +if(DIST_ROOT) + set(CMAKE_INSTALL_PREFIX "${DIST_ROOT}") +else() + set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/PTHREADS-BUILT") +endif() +message(STATUS "Install Path ${CMAKE_INSTALL_PREFIX}") + + +set(DLLDEST ${CMAKE_INSTALL_PREFIX}/${TARGET_ARCH}/${CMAKE_BUILD_TYPE}/bin) +set(LIBDEST ${CMAKE_INSTALL_PREFIX}/${TARGET_ARCH}/${CMAKE_BUILD_TYPE}/lib) +set(HDRDEST ${CMAKE_INSTALL_PREFIX}/${TARGET_ARCH}/${CMAKE_BUILD_TYPE}/include) +set(TESTDEST ${CMAKE_INSTALL_PREFIX}/${TARGET_ARCH}/${CMAKE_BUILD_TYPE}/test) + +################################# +# Defs # +################################# +add_definitions(-D__PTW32_BUILD_INLINED) + +if(MSVC) + + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /errorReport:none /nologo ") + + # C++ Exceptions + # (Note: If you are using Microsoft VC++6.0, the library needs to be built + # with /EHa instead of /EHs or else cancellation won't work properly.) + if(MSVC_VERSION EQUAL 1200) + set(VCEFLAGS "/EHa /TP ") + else() + set(VCEFLAGS "/EHs /TP ") + endif() + + add_definitions(-DHAVE_CONFIG_H -D__PTW32_RC_MSC) + +endif() + +# Update filename with proper version info +configure_file(${CMAKE_SOURCE_DIR}/cmake/version.rc.in ${CMAKE_BINARY_DIR}/version.rc @ONLY) + +################################# +# Libraries # +################################# +set(targ_suffix "") +if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") + set(targ_suffix ${CMAKE_DEBUG_POSTFIX}) +endif() + +macro(shared_lib type def) + set(targ pthread${type}${PTW32_VER}) + add_library(${targ} SHARED pthread.c ${CMAKE_BINARY_DIR}/version.rc) + message(STATUS ${targ}) + target_compile_definitions(${targ} PUBLIC "-D${def}") + if(${type} STREQUAL "VCE") + set_target_properties(${targ} PROPERTIES COMPILE_FLAGS ${VCEFLAGS}) + endif() + if(${CMAKE_GENERATOR} MATCHES "Visual Studio") + install(FILES ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${targ}${targ_suffix}.dll DESTINATION ${DLLDEST}) + install(FILES ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${targ}${targ_suffix}.lib DESTINATION ${LIBDEST}) + else() + install(FILES ${CMAKE_BINARY_DIR}/${targ}${targ_suffix}.dll DESTINATION ${DLLDEST}) + install(FILES ${CMAKE_BINARY_DIR}/${targ}${targ_suffix}.lib DESTINATION ${LIBDEST}) + endif() +endmacro() + +macro(static_lib type def) + set(targ libpthread${type}${PTW32_VER}) + add_library(${targ} STATIC pthread.c) + message(STATUS ${targ}) + target_compile_definitions(${targ} PUBLIC "-D${def}" -D__PTW32_STATIC_LIB) + if(${type} STREQUAL "VCE") + set_target_properties(${targ} PROPERTIES COMPILE_FLAGS ${VCEFLAGS}) + endif() + if(${CMAKE_GENERATOR} MATCHES "Visual Studio") + install(FILES ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${targ}${targ_suffix}.lib DESTINATION ${LIBDEST}) + else() + install(FILES ${CMAKE_BINARY_DIR}/${targ}${targ_suffix}.lib DESTINATION ${LIBDEST}) + endif() +endmacro() + +shared_lib ( VCE __PTW32_CLEANUP_CXX ) +shared_lib ( VSE __PTW32_CLEANUP_SEH ) +shared_lib ( VC __PTW32_CLEANUP_C ) + +static_lib ( VCE __PTW32_CLEANUP_CXX ) +static_lib ( VSE __PTW32_CLEANUP_SEH ) +static_lib ( VC __PTW32_CLEANUP_C ) + +################################# +# Install # +################################# +install(FILES _ptw32.h pthread.h sched.h semaphore.h DESTINATION ${HDRDEST}) + +################################# +# Test # +################################# +option(ENABLE_TESTS "Enable Test code build" FALSE) + +#TODO determine if cross compile... +if(ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/ChangeLog b/ChangeLog index 6f0913e..d37c9b8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2019-11-03 Ross Johnson + + * NOTICE: Remove third party code acknowledgments because files have been + removed from distro. + 2018-08-19 Ross Johnson * context.h (__PTW32_PROCPTR): Added missing '__' prefix for v3. diff --git a/NOTICE b/NOTICE index d73542d..3b99d7b 100644 --- a/NOTICE +++ b/NOTICE @@ -4,26 +4,4 @@ Copyright 1999-2018, Pthreads4w contributors This product includes software developed through the colaborative effort of several individuals, each of whom is listed in the file -CONTRIBUTORS included with this software. - -The following files are not covered under the Copyrights -listed above: - - [1] tests/rwlock7.c - [1] tests/rwlock7_1.c - [1] tests/rwlock8.c - [1] tests/rwlock8_1.c - [2] tests/threestage.c - -[1] The file tests/rwlock7.c and those similarly named are derived from -code written by Dave Butenhof for his book 'Programming With POSIX(R) -Threads'. The original code was obtained by free download from his -website http://home.earthlink.net/~anneart/family/Threads/source.html - -[2] The file tests/threestage.c is taken directly from examples in the -book "Windows System Programming, Edition 4" by Johnson (John) Hart -Session 6, Chapter 10. ThreeStage.c -Several required additional header and source files from the -book examples have been included inline to simplify compilation. -The only modification to the code has been to provide default -values when run without arguments. +CONTRIBUTORS included with this software. \ No newline at end of file diff --git a/_ptw32.h b/_ptw32.h index e638027..5821f94 100644 --- a/_ptw32.h +++ b/_ptw32.h @@ -43,10 +43,10 @@ */ #define __PTW32_VERSION_MAJOR 3 #define __PTW32_VERSION_MINOR 0 -#define __PTW32_VERSION_MICRO 1 +#define __PTW32_VERSION_MICRO 2 #define __PTW32_VERION_BUILD 0 -#define __PTW32_VERSION 3,0,0,1 -#define __PTW32_VERSION_STRING "3, 0, 1, 0\0" +#define __PTW32_VERSION 3,0,2,0 +#define __PTW32_VERSION_STRING "3, 0, 2, 0\0" #if defined(__GNUC__) # pragma GCC system_header diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..2810968 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,110 @@ +version: 3.0.1.{build} + +shallow_clone: true +clone_depth: 1 + +branches: + only: + - cmake + +configuration: +- MinSizeRel +- Release +- Debug + +environment: + DIST_DIR: '%APPVEYOR_BUILD_FOLDER%\dist' + CMAKE_DIST_DIR: C:/projects/pthreads4w/dist + APPVEYOR_SAVE_CACHE_ON_ERROR: true + + matrix: + + - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2015' + VCVARSALL: '%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat' + ARCHITECTURE: amd64_x86 + ARCHIVE: VS2015_%CONFIGURATION%_x86_%APPVEYOR_BUILD_NUMBER% + GENERATOR: 'NMake Makefiles' + TESTING: OFF + + - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2015' + VCVARSALL: '%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat' + ARCHITECTURE: amd64 + ARCHIVE: VS2015_%CONFIGURATION%_x64_%APPVEYOR_BUILD_NUMBER% + GENERATOR: 'NMake Makefiles' + TESTING: OFF + + - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2015' + VCVARSALL: '%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat' + ARCHITECTURE: amd64_arm + ARCHIVE: VS2015_%CONFIGURATION%_ARM_%APPVEYOR_BUILD_NUMBER% + GENERATOR: 'NMake Makefiles' + TESTING: OFF + + + - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2017' + VCVARSALL: '%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsamd64_arm.bat' + ARCHIVE: VS2017_%CONFIGURATION%_ARM_%APPVEYOR_BUILD_NUMBER% + GENERATOR: 'NMake Makefiles' + TESTING: OFF + + - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2017' + VCVARSALL: '%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsamd64_arm64.bat' + ARCHIVE: VS2017_%CONFIGURATION%_ARM64_%APPVEYOR_BUILD_NUMBER% + GENERATOR: 'NMake Makefiles' + TESTING: OFF + + - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2017' + VCVARSALL: '%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat' + ARCHIVE: VS2017_%CONFIGURATION%_x86_%APPVEYOR_BUILD_NUMBER% + GENERATOR: 'NMake Makefiles' + TESTING: ON + + - APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2017' + VCVARSALL: '%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat' + ARCHIVE: VS2017_%CONFIGURATION%_x64_%APPVEYOR_BUILD_NUMBER% + GENERATOR: 'NMake Makefiles' + TESTING: ON + +init: + - echo BUILD_NUMBER=%APPVEYOR_BUILD_NUMBER% + +install: + + # CMake + - cmake --version + +build: + parallel: true + +build_script: + - if exist "%VCVARSALL%" ( call "%VCVARSALL%" %ARCHITECTURE% ) + + - cd %APPVEYOR_BUILD_FOLDER% + - mkdir build + - cd build + - cmake -G"%GENERATOR%" + -DCMAKE_BUILD_TYPE=%CONFIGURATION% + -DBUILD_NUMBER=%APPVEYOR_BUILD_NUMBER% + -DDIST_ROOT="%CMAKE_DIST_DIR%/%APPVEYOR_BUILD_WORKER_IMAGE%" + -DENABLE_TESTS=%TESTING% + .. + + cmake --build . --config %CONFIGURATION% --target install + +after_build: + - cd %DIST_DIR% + - 7z a -tzip %ARCHIVE%.zip "%APPVEYOR_BUILD_WORKER_IMAGE%" + - certutil -hashfile %ARCHIVE%.zip MD5 > %ARCHIVE%.md5 + +artifacts: + - path: dist\$(ARCHIVE).zip + - path: dist\$(ARCHIVE).md5 + +test: +before_test: + - set PATH=%APPVEYOR_BUILD_FOLDER%\build;%PATH% +test_script: + - if exist %APPVEYOR_BUILD_FOLDER%\build\tests\ cd %APPVEYOR_BUILD_FOLDER%\build\tests + - if exist %APPVEYOR_BUILD_FOLDER%\build\tests\ ctest -C %CONFIGURATION% -V +after_test: + # TODO process CTest output diff --git a/cmake/get_version.cmake b/cmake/get_version.cmake new file mode 100644 index 0000000..82e92c7 --- /dev/null +++ b/cmake/get_version.cmake @@ -0,0 +1,21 @@ + +file(READ ${CMAKE_SOURCE_DIR}/_ptw32.h _PTW32_H_CONTENTS) + +string(REGEX MATCH "#define __PTW32_VERSION_MAJOR ([a-zA-Z0-9_]+)" PTW32_VERSION_MAJOR "${_PTW32_H_CONTENTS}") +string(REPLACE "#define __PTW32_VERSION_MAJOR " "" PTW32_VERSION_MAJOR "${PTW32_VERSION_MAJOR}") + +string(REGEX MATCH "#define __PTW32_VERSION_MINOR ([a-zA-Z0-9_]+)" PTW32_VERSION_MINOR "${_PTW32_H_CONTENTS}") +string(REPLACE "#define __PTW32_VERSION_MINOR " "" PTW32_VERSION_MINOR "${PTW32_VERSION_MINOR}") + +string(REGEX MATCH "#define __PTW32_VERSION_MICRO ([a-zA-Z0-9_]+)" PTW32_VERSION_MICRO "${_PTW32_H_CONTENTS}") +string(REPLACE "#define __PTW32_VERSION_MICRO " "" PTW32_VERSION_MICRO "${PTW32_VERSION_MICRO}") + +string(REGEX MATCH "#define __PTW32_VERION_BUILD ([a-zA-Z0-9_]+)" PTW32_VERSION_BUILD "${_PTW32_H_CONTENTS}") +string(REPLACE "#define __PTW32_VERION_BUILD " "" PTW32_VERSION_BUILD "${PTW32_VERSION_BUILD}") + +if(BUILD_NUMBER) + set(PTW32_VERSION_BUILD ${BUILD_NUMBER}) +endif() + +set(PTHREADS4W_VERSION ${PTW32_VERSION_MAJOR}.${PTW32_VERSION_MINOR}.${PTW32_VERSION_MICRO}.${PTW32_VERSION_BUILD}) + diff --git a/cmake/target_arch.cmake b/cmake/target_arch.cmake new file mode 100644 index 0000000..0545044 --- /dev/null +++ b/cmake/target_arch.cmake @@ -0,0 +1,36 @@ + +set(TARGET_ARCH_DETECT_CODE " + + #if defined(_M_ARM) + #error cmake_arch ARM + #elif defined(_M_ARM64) + #error cmake_arch ARM64 + #elif defined(_M_AMD64) + #error cmake_arch x86_64 + #elif defined(_M_X64) + #error cmake_arch x64 + #elif defined(_M_IX86) + #error cmake_arch x86 + #else + #error cmake_arch unknown + #endif +") + +function(get_target_arch out) + + file(WRITE + "${CMAKE_BINARY_DIR}/target_arch_detect.c" + "${TARGET_ARCH_DETECT_CODE}") + + try_run( + run_result_unused compile_result_unused + "${CMAKE_BINARY_DIR}" "${CMAKE_BINARY_DIR}/target_arch_detect.c" + COMPILE_OUTPUT_VARIABLE TARGET_ARCH) + + # parse compiler output + string(REGEX MATCH "cmake_arch ([a-zA-Z0-9_]+)" TARGET_ARCH "${TARGET_ARCH}") + string(REPLACE "cmake_arch " "" TARGET_ARCH "${TARGET_ARCH}") + + set(${out} "${TARGET_ARCH}" PARENT_SCOPE) + +endfunction() diff --git a/cmake/version.rc.in b/cmake/version.rc.in new file mode 100644 index 0000000..0e41fcb --- /dev/null +++ b/cmake/version.rc.in @@ -0,0 +1,429 @@ +/* This is an implementation of the threads API of POSIX 1003.1-2001. + * + * -------------------------------------------------------------------------- + * + * Pthreads4w - POSIX Threads for Windows + * Copyright 1998 John E. Bossom + * Copyright 1999-2018, Pthreads4w contributors + * + * Homepage: https://sourceforge.net/projects/pthreads4w/ + * + * 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: + * + * https://sourceforge.net/p/pthreads4w/wiki/Contributors/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "pthread.h" + +/* + * Note: the correct __PTW32_CLEANUP_* macro must be defined corresponding to + * the definition used for the object file builds. This is done in the + * relevent makefiles for the command line builds, but users should ensure + * that their resource compiler knows what it is too. + * If using the default (no __PTW32_CLEANUP_* defined), pthread.h will define it + * as __PTW32_CLEANUP_C. + */ + +#if defined (__PTW32_RC_MSC) +# if defined (__PTW32_ARCHx64) || defined (__PTW32_ARCHX64) || defined (__PTW32_ARCHAMD64) +# if defined(__PTW32_CLEANUP_C) +# define __PTW32_VERSIONINFO_NAME "pthreadVC@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "MS C x64\0" +# elif defined(__PTW32_CLEANUP_CXX) +# define __PTW32_VERSIONINFO_NAME "pthreadVCE@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "MS C++ x64\0" +# elif defined(__PTW32_CLEANUP_SEH) +# define __PTW32_VERSIONINFO_NAME "pthreadVSE@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "MS C SEH x64\0" +# endif +# elif defined (__PTW32_ARCHx86) || defined (__PTW32_ARCHX86) +# if defined(__PTW32_CLEANUP_C) +# define __PTW32_VERSIONINFO_NAME "pthreadVC@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "MS C x86\0" +# elif defined(__PTW32_CLEANUP_CXX) +# define __PTW32_VERSIONINFO_NAME "pthreadVCE@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "MS C++ x86\0" +# elif defined(__PTW32_CLEANUP_SEH) +# define __PTW32_VERSIONINFO_NAME "pthreadVSE@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "MS C SEH x86\0" +# endif +# elif defined (__PTW32_ARCHARM) || defined (__PTW32_ARCHARM) +# if defined(__PTW32_CLEANUP_C) +# define __PTW32_VERSIONINFO_NAME "pthreadVC@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "MS C ARM\0" +# elif defined(__PTW32_CLEANUP_CXX) +# define __PTW32_VERSIONINFO_NAME "pthreadVCE@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "MS C++ ARM\0" +# elif defined(__PTW32_CLEANUP_SEH) +# define __PTW32_VERSIONINFO_NAME "pthreadVSE@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "MS C SEH ARM\0" +# endif +# elif defined (__PTW32_ARCHARM64) || defined (__PTW32_ARCHARM64) +# if defined(__PTW32_CLEANUP_C) +# define __PTW32_VERSIONINFO_NAME "pthreadVC@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "MS C ARM64\0" +# elif defined(__PTW32_CLEANUP_CXX) +# define __PTW32_VERSIONINFO_NAME "pthreadVCE@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "MS C++ ARM64\0" +# elif defined(__PTW32_CLEANUP_SEH) +# define __PTW32_VERSIONINFO_NAME "pthreadVSE@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "MS C SEH ARM64\0" +# endif +# endif +#elif defined(__GNUC__) +# if defined(_M_X64) +# define __PTW32_ARCH "x64 (mingw64)" +# else +# define __PTW32_ARCH "x86 (mingw32)" +# endif +# if defined(__PTW32_CLEANUP_C) +# define __PTW32_VERSIONINFO_NAME "pthreadGC@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "GNU C " __PTW32_ARCH "\0" +# elif defined(__PTW32_CLEANUP_CXX) +# define __PTW32_VERSIONINFO_NAME "pthreadGCE@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "GNU C++ " __PTW32_ARCH "\0" +# else +# error Resource compiler doesn't know which cleanup style you're using - see version.rc +# endif +#elif defined(__BORLANDC__) +# if defined(_M_X64) +# define __PTW32_ARCH "x64 (Borland)" +# else +# define __PTW32_ARCH "x86 (Borland)" +# endif +# if defined(__PTW32_CLEANUP_C) +# define __PTW32_VERSIONINFO_NAME "pthreadBC@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "BORLAND C " __PTW32_ARCH "\0" +# elif defined(__PTW32_CLEANUP_CXX) +# define __PTW32_VERSIONINFO_NAME "pthreadBCE@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "BORLAND C++ " __PTW32_ARCH "\0" +# else +# error Resource compiler doesn't know which cleanup style you're using - see version.rc +# endif +#elif defined(__WATCOMC__) +# if defined(_M_X64) +# define __PTW32_ARCH "x64 (Watcom)" +# else +# define __PTW32_ARCH "x86 (Watcom)" +# endif +# if defined(__PTW32_CLEANUP_C) +# define __PTW32_VERSIONINFO_NAME "pthreadWC@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "WATCOM C " __PTW32_ARCH "\0" +# elif defined(__PTW32_CLEANUP_CXX) +# define __PTW32_VERSIONINFO_NAME "pthreadWCE@PTW32_VER@.DLL\0" +# define __PTW32_VERSIONINFO_DESCRIPTION "WATCOM C++ " __PTW32_ARCH "\0" +# else +# error Resource compiler doesn't know which cleanup style you're using - see version.rc +# endif +#else +# error Resource compiler doesn't know which compiler you're using - see version.rc +#endif + + +VS_VERSION_INFO VERSIONINFO + FILEVERSION __PTW32_VERSION + PRODUCTVERSION __PTW32_VERSION + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS 0 + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "ProductName", "POSIX Threads for Windows\0" + VALUE "ProductVersion", __PTW32_VERSION_STRING + VALUE "FileVersion", __PTW32_VERSION_STRING + VALUE "FileDescription", __PTW32_VERSIONINFO_DESCRIPTION + VALUE "InternalName", __PTW32_VERSIONINFO_NAME + VALUE "OriginalFilename", __PTW32_VERSIONINFO_NAME + VALUE "CompanyName", "Open Source Software community\0" + VALUE "LegalCopyright", "Copyright - Project contributors 1999-2018\0" + VALUE "Comments", "https://sourceforge.net/p/pthreads4w/wiki/Contributors/\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +/* +VERSIONINFO Resource + +The VERSIONINFO resource-definition statement creates a version-information +resource. The resource contains such information about the file as its +version number, its intended operating system, and its original filename. +The resource is intended to be used with the Version Information functions. + +versionID VERSIONINFO fixed-info { block-statement...} + +versionID + Version-information resource identifier. This value must be 1. + +fixed-info + Version information, such as the file version and the intended operating + system. This parameter consists of the following statements. + + + Statement Description + -------------------------------------------------------------------------- + FILEVERSION + version Binary version number for the file. The version + consists of two 32-bit integers, defined by four + 16-bit integers. For example, "FILEVERSION 3,10,0,61" + is translated into two doublewords: 0x0003000a and + 0x0000003d, in that order. Therefore, if version is + defined by the DWORD values dw1 and dw2, they need + to appear in the FILEVERSION statement as follows: + HIWORD(dw1), LOWORD(dw1), HIWORD(dw2), LOWORD(dw2). + PRODUCTVERSION + version Binary version number for the product with which the + file is distributed. The version parameter is two + 32-bit integers, defined by four 16-bit integers. + For more information about version, see the + FILEVERSION description. + FILEFLAGSMASK + fileflagsmask Bits in the FILEFLAGS statement are valid. If a bit + is set, the corresponding bit in FILEFLAGS is valid. + FILEFLAGSfileflags Attributes of the file. The fileflags parameter must + be the combination of all the file flags that are + valid at compile time. For 16-bit Windows, this + value is 0x3f. + FILEOSfileos Operating system for which this file was designed. + The fileos parameter can be one of the operating + system values given in the Remarks section. + FILETYPEfiletype General type of file. The filetype parameter can be + one of the file type values listed in the Remarks + section. + FILESUBTYPE + subtype Function of the file. The subtype parameter is zero + unless the type parameter in the FILETYPE statement + is VFT_DRV, VFT_FONT, or VFT_VXD. For a list of file + subtype values, see the Remarks section. + +block-statement + Specifies one or more version-information blocks. A block can contain + string information or variable information. For more information, see + StringFileInfo Block or VarFileInfo Block. + +Remarks + +To use the constants specified with the VERSIONINFO statement, you must +include the Winver.h or Windows.h header file in the resource-definition file. + +The following list describes the parameters used in the VERSIONINFO statement: + +fileflags + A combination of the following values. + + Value Description + + VS_FF_DEBUG File contains debugging information or is compiled + with debugging features enabled. + VS_FF_PATCHED File has been modified and is not identical to the + original shipping file of the same version number. + VS_FF_PRERELEASE File is a development version, not a commercially + released product. + VS_FF_PRIVATEBUILD File was not built using standard release procedures. + If this value is given, the StringFileInfo block must + contain a PrivateBuild string. + VS_FF_SPECIALBUILD File was built by the original company using standard + release procedures but is a variation of the standard + file of the same version number. If this value is + given, the StringFileInfo block must contain a + SpecialBuild string. + +fileos + One of the following values. + + Value Description + + VOS_UNKNOWN The operating system for which the file was designed + is unknown. + VOS_DOS File was designed for MS-DOS. + VOS_NT File was designed for Windows Server 2003 family, + Windows XP, Windows 2000, or Windows NT. + VOS__WINDOWS16 File was designed for 16-bit Windows. + VOS__WINDOWS32 File was designed for 32-bit Windows. + VOS_DOS_WINDOWS16 File was designed for 16-bit Windows running with + MS-DOS. + VOS_DOS_WINDOWS32 File was designed for 32-bit Windows running with + MS-DOS. + VOS_NT_WINDOWS32 File was designed for Windows Server 2003 family, + Windows XP, Windows 2000, or Windows NT. + + The values 0x00002L, 0x00003L, 0x20000L and 0x30000L are reserved. + +filetype + One of the following values. + + Value Description + + VFT_UNKNOWN File type is unknown. + VFT_APP File contains an application. + VFT_DLL File contains a dynamic-link library (DLL). + VFT_DRV File contains a device driver. If filetype is + VFT_DRV, subtype contains a more specific + description of the driver. + VFT_FONT File contains a font. If filetype is VFT_FONT, + subtype contains a more specific description of the + font. + VFT_VXD File contains a virtual device. + VFT_STATIC_LIB File contains a static-link library. + + All other values are reserved for use by Microsoft. + +subtype + Additional information about the file type. + + If filetype specifies VFT_DRV, this parameter can be one of the + following values. + + Value Description + + VFT2_UNKNOWN Driver type is unknown. + VFT2_DRV_COMM File contains a communications driver. + VFT2_DRV_PRINTER File contains a printer driver. + VFT2_DRV_KEYBOARD File contains a keyboard driver. + VFT2_DRV_LANGUAGE File contains a language driver. + VFT2_DRV_DISPLAY File contains a display driver. + VFT2_DRV_MOUSE File contains a mouse driver. + VFT2_DRV_NETWORK File contains a network driver. + VFT2_DRV_SYSTEM File contains a system driver. + VFT2_DRV_INSTALLABLE File contains an installable driver. + VFT2_DRV_SOUND File contains a sound driver. + VFT2_DRV_VERSIONED_PRINTER File contains a versioned printer driver. + + If filetype specifies VFT_FONT, this parameter can be one of the + following values. + + Value Description + + VFT2_UNKNOWN Font type is unknown. + VFT2_FONT_RASTER File contains a raster font. + VFT2_FONT_VECTOR File contains a vector font. + VFT2_FONT_TRUETYPE File contains a TrueType font. + + If filetype specifies VFT_VXD, this parameter must be the virtual-device + identifier included in the virtual-device control block. + + All subtype values not listed here are reserved for use by Microsoft. + +langID + One of the following language codes. + + Code Language Code Language + + 0x0401 Arabic 0x0415 Polish + 0x0402 Bulgarian 0x0416 Portuguese (Brazil) + 0x0403 Catalan 0x0417 Rhaeto-Romanic + 0x0404 Traditional Chinese 0x0418 Romanian + 0x0405 Czech 0x0419 Russian + 0x0406 Danish 0x041A Croato-Serbian (Latin) + 0x0407 German 0x041B Slovak + 0x0408 Greek 0x041C Albanian + 0x0409 U.S. English 0x041D Swedish + 0x040A Castilian Spanish 0x041E Thai + 0x040B Finnish 0x041F Turkish + 0x040C French 0x0420 Urdu + 0x040D Hebrew 0x0421 Bahasa + 0x040E Hungarian 0x0804 Simplified Chinese + 0x040F Icelandic 0x0807 Swiss German + 0x0410 Italian 0x0809 U.K. English + 0x0411 Japanese 0x080A Mexican Spanish + 0x0412 Korean 0x080C Belgian French + 0x0413 Dutch 0x0C0C Canadian French + 0x0414 Norwegian – Bokmal 0x100C Swiss French + 0x0810 Swiss Italian 0x0816 Portuguese (Portugal) + 0x0813 Belgian Dutch 0x081A Serbo-Croatian (Cyrillic) + 0x0814 Norwegian – Nynorsk + +charsetID + One of the following character-set identifiers. + + Identifier Character Set + + 0 7-bit ASCII + 932 Japan (Shift %G–%@ JIS X-0208) + 949 Korea (Shift %G–%@ KSC 5601) + 950 Taiwan (Big5) + 1200 Unicode + 1250 Latin-2 (Eastern European) + 1251 Cyrillic + 1252 Multilingual + 1253 Greek + 1254 Turkish + 1255 Hebrew + 1256 Arabic + +string-name + One of the following predefined names. + + Name Description + + Comments Additional information that should be displayed for + diagnostic purposes. + CompanyName Company that produced the file%G—%@for example, + "Microsoft Corporation" or "Standard Microsystems + Corporation, Inc." This string is required. + FileDescription File description to be presented to users. This + string may be displayed in a list box when the user + is choosing files to install%G—%@for example, + "Keyboard Driver for AT-Style Keyboards". This + string is required. + FileVersion Version number of the file%G—%@for example, + "3.10" or "5.00.RC2". This string is required. + InternalName Internal name of the file, if one exists — for + example, a module name if the file is a dynamic-link + library. If the file has no internal name, this + string should be the original filename, without + extension. This string is required. + LegalCopyright Copyright notices that apply to the file. This + should include the full text of all notices, legal + symbols, copyright dates, and so on — for example, + "Copyright (C) Microsoft Corporation 1990–1999". + This string is optional. + LegalTrademarks Trademarks and registered trademarks that apply to + the file. This should include the full text of all + notices, legal symbols, trademark numbers, and so on. + This string is optional. + OriginalFilename Original name of the file, not including a path. + This information enables an application to determine + whether a file has been renamed by a user. The + format of the name depends on the file system for + which the file was created. This string is required. + PrivateBuild Information about a private version of the file — for + example, "Built by TESTER1 on \TESTBED". This string + should be present only if VS_FF_PRIVATEBUILD is + specified in the fileflags parameter of the root + block. + ProductName Name of the product with which the file is + distributed. This string is required. + ProductVersion Version of the product with which the file is + distributed — for example, "3.10" or "5.00.RC2". + This string is required. + SpecialBuild Text that indicates how this version of the file + differs from the standard version — for example, + "Private build for TESTER1 solving mouse problems + on M250 and M250E computers". This string should be + present only if VS_FF_SPECIALBUILD is specified in + the fileflags parameter of the root block. + */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..fc8e7fd --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,80 @@ + +include (CTest) + +include_directories(..) + +set(XXLIBS ws2_32.lib) + +set(VCEFLAGS "${VCEFLAGS} -D__PtW32NoCatchWarn") + +macro(add_testcase test type def) + + set(lib_test test-${test}${type}${PTW32_VER}) + set(dll_test test-dll-${test}${type}${PTW32_VER}) + + set(lib_lib libpthread${type}${PTW32_VER}) + set(dll_lib pthread${type}${PTW32_VER}) + + set(c_dep "") + if(${test} MATCHES "benchtest") + set(c_dep "benchlib.c") + endif() + + set(extra "") + if(${test} MATCHES "openmp1") + if(MSVC) + set(extra "/openmp -D_OPENMP") + endif() + endif() + + add_executable(${lib_test} ${test}.c ${c_dep}) + target_link_libraries(${lib_test} ${lib_lib} ${XXLIBS}) + target_compile_definitions(${lib_test} PUBLIC "/nologo -D_CONSOLE -D_MBCS -D${def} ${extra}") + add_dependencies(${lib_test} ${lib_lib}) + + add_executable(${dll_test} ${test}.c ${c_dep}) + target_link_libraries(${dll_test} ${dll_lib} ${XXLIBS}) + target_compile_definitions(${dll_test} PUBLIC "/nologo -D_CONSOLE -D_MBCS -D${def} ${extra}") + add_dependencies(${dll_test} ${dll_lib}) + + if(${CMAKE_GENERATOR} MATCHES "Visual Studio") + install(FILES ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/tests/${lib_test}.exe DESTINATION ${TESTDEST}) + install(FILES ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/tests/${dll_test}.exe DESTINATION ${TESTDEST}) + else() + install(FILES ${CMAKE_BINARY_DIR}/tests/${lib_test}.exe DESTINATION ${TESTDEST}) + install(FILES ${CMAKE_BINARY_DIR}/tests/${dll_test}.exe DESTINATION ${TESTDEST}) + endif() + + if(${type} MATCHES "VCE") + set_target_properties(${lib_test} PROPERTIES COMPILE_FLAGS ${VCEFLAGS}) + set_target_properties(${dll_test} PROPERTIES COMPILE_FLAGS ${VCEFLAGS}) + endif() + + add_test(NAME ${lib_test} COMMAND ${lib_test}) + add_test(NAME ${dll_test} COMMAND ${dll_test}) + +endmacro() + + +file(GLOB TESTS *.c) + +foreach(t ${TESTS}) + + get_filename_component(test ${t} NAME) + string(REPLACE ".c" "" test "${test}") + + # exclusions + if(${test} STREQUAL "benchlib") + list(REMOVE_ITEM TESTS ${t}) + continue() + elseif(${test} STREQUAL "context2") # SEGFAULT + continue() + elseif(${test} STREQUAL "tryentercs2") # SEGFAULT + continue() + endif() + + add_testcase(${test} VCE __PTW32_CLEANUP_CXX ) + add_testcase(${test} VSE __PTW32_CLEANUP_SEH ) + add_testcase(${test} VC __PTW32_CLEANUP_C ) + +endforeach(t) diff --git a/tests/ChangeLog b/tests/ChangeLog index c4895d0..beda9e3 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,11 @@ +2018-08-19 Ross Johnson + + * threestage.c: Delete. + * rwlock7.c: Delete. + * rwlock8.c: Delete. + * rwlock7_1.c: Delete. + * rwlock8_1.c: Delete. + 2018-08-10 Ross Johnson * Makefile (clean): remove *.idb files. diff --git a/tests/common.mk b/tests/common.mk index f6cf9d1..731713d 100644 --- a/tests/common.mk +++ b/tests/common.mk @@ -40,7 +40,7 @@ ALL_KNOWN_TESTS = \ robust1 robust2 robust3 robust4 robust5 \ rwlock1 rwlock2 rwlock3 rwlock4 \ rwlock2_t rwlock3_t rwlock4_t rwlock5_t rwlock6_t rwlock6_t2 \ - rwlock5 rwlock6 rwlock7 rwlock7_1 rwlock8 rwlock8_1 \ + rwlock5 rwlock6 \ self1 self2 \ semaphore1 semaphore2 semaphore3 \ semaphore4 semaphore4t semaphore5 \ diff --git a/tests/openmp1.c b/tests/openmp1.c index b5791e2..30adb33 100755 --- a/tests/openmp1.c +++ b/tests/openmp1.c @@ -88,9 +88,6 @@ int main(int argc, char *argv[]) { pthread_t b_thr; int status; - printf("%s:%d - %s - a_thr:%p - b_thr:%p\n", - __FILE__,__LINE__,__FUNCTION__,a_thr.p,b_thr.p); - status = pthread_create(&a_thr, NULL, _thread, (void*) 1 ); if ( status != 0 ) { printf("Failed to create thread 1\n"); @@ -103,6 +100,9 @@ int main(int argc, char *argv[]) { return (-1); } + printf("%s:%d - %s - a_thr:%p - b_thr:%p\n", + __FILE__,__LINE__,__FUNCTION__,a_thr.p,b_thr.p); + status = pthread_join(a_thr, NULL); if ( status != 0 ) { printf("Failed to join thread 1\n"); diff --git a/tests/runorder.mk b/tests/runorder.mk index 215d7e7..63a428b 100644 --- a/tests/runorder.mk +++ b/tests/runorder.mk @@ -113,7 +113,7 @@ once3.pass: once2.pass once4.pass: once3.pass priority1.pass: join1.pass priority2.pass: priority1.pass barrier3.pass -reinit1.pass: rwlock7.pass +reinit1.pass: rwlock6.pass reuse1.pass: create3.pass reuse2.pass: reuse1.pass robust1.pass: mutex8r.pass @@ -127,13 +127,11 @@ rwlock3.pass: rwlock2.pass join2.pass rwlock4.pass: rwlock3.pass rwlock5.pass: rwlock4.pass rwlock6.pass: rwlock5.pass -rwlock7.pass: rwlock6.pass -rwlock8.pass: rwlock7.pass rwlock2_t.pass: rwlock2.pass -rwlock3_t.pass: rwlock2_t.pass -rwlock4_t.pass: rwlock3_t.pass -rwlock5_t.pass: rwlock4_t.pass -rwlock6_t.pass: rwlock5_t.pass +rwlock3_t.pass: rwlock3.pass rwlock2_t.pass +rwlock4_t.pass: rwlock4.pass rwlock3_t.pass +rwlock5_t.pass: rwlock5.pass rwlock4_t.pass +rwlock6_t.pass: rwlock6.pass rwlock5_t.pass rwlock6_t2.pass: rwlock6_t.pass self1.pass: sizes.pass self2.pass: self1.pass equal1.pass create1.pass diff --git a/tests/rwlock7.c b/tests/rwlock7.c deleted file mode 100644 index 9d58f6e..0000000 --- a/tests/rwlock7.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * rwlock7.c - * - * Hammer on a bunch of rwlocks to test robustness and fairness. - * Printed stats should be roughly even for each thread. - */ - -#include "test.h" -#include - -#ifdef __GNUC__ -#include -#endif - -#define THREADS 5 -#define DATASIZE 7 -#define ITERATIONS 1000000 - -/* - * Keep statistics for each thread. - */ -typedef struct thread_tag { - int thread_num; - pthread_t thread_id; - int updates; - int reads; - int changed; - int seed; -} thread_t; - -/* - * Read-write lock and shared data - */ -typedef struct data_tag { - pthread_rwlock_t lock; - int data; - int updates; -} data_t; - -static thread_t threads[THREADS]; -static data_t data[DATASIZE]; - -/* - * Thread start routine that uses read-write locks - */ -void *thread_routine (void *arg) -{ - thread_t *self = (thread_t*)arg; - int iteration; - int element = 0; - int seed = self->seed; - int interval = 1 + rand_r (&seed) % 71; - - self->changed = 0; - - for (iteration = 0; iteration < ITERATIONS; iteration++) - { - if (iteration % (ITERATIONS / 10) == 0) - { - putchar('.'); - fflush(stdout); - } - /* - * Each "self->interval" iterations, perform an - * update operation (write lock instead of read - * lock). - */ - if ((iteration % interval) == 0) - { - assert(pthread_rwlock_wrlock (&data[element].lock) == 0); - data[element].data = self->thread_num; - data[element].updates++; - self->updates++; - interval = 1 + rand_r (&seed) % 71; - assert(pthread_rwlock_unlock (&data[element].lock) == 0); - } else { - /* - * Look at the current data element to see whether - * the current thread last updated it. Count the - * times, to report later. - */ - assert(pthread_rwlock_rdlock (&data[element].lock) == 0); - - self->reads++; - - if (data[element].data != self->thread_num) - { - self->changed++; - interval = 1 + self->changed % 71; - } - - assert(pthread_rwlock_unlock (&data[element].lock) == 0); - } - - element = (element + 1) % DATASIZE; - - } - - return NULL; -} - -int -main (int argc, char *argv[]) -{ - int count; - int data_count; - int thread_updates = 0; - int data_updates = 0; - int seed = 1; - - __PTW32_STRUCT_TIMEB currSysTime1; - __PTW32_STRUCT_TIMEB currSysTime2; - - /* - * Initialize the shared data. - */ - for (data_count = 0; data_count < DATASIZE; data_count++) - { - data[data_count].data = 0; - data[data_count].updates = 0; - - assert(pthread_rwlock_init (&data[data_count].lock, NULL) == 0); - } - - __PTW32_FTIME(&currSysTime1); - - /* - * Create THREADS threads to access shared data. - */ - for (count = 0; count < THREADS; count++) - { - threads[count].thread_num = count; - threads[count].updates = 0; - threads[count].reads = 0; - threads[count].seed = 1 + rand_r (&seed) % 71; - - assert(pthread_create (&threads[count].thread_id, - NULL, thread_routine, (void*)(size_t)&threads[count]) == 0); - } - - /* - * Wait for all threads to complete, and collect - * statistics. - */ - for (count = 0; count < THREADS; count++) - { - assert(pthread_join (threads[count].thread_id, NULL) == 0); - } - - putchar('\n'); - fflush(stdout); - - for (count = 0; count < THREADS; count++) - { - if (threads[count].changed > 0) - { - printf ("Thread %d found changed elements %d times\n", - count, threads[count].changed); - } - } - - putchar('\n'); - fflush(stdout); - - for (count = 0; count < THREADS; count++) - { - thread_updates += threads[count].updates; - printf ("%02d: seed %d, updates %d, reads %d\n", - count, threads[count].seed, - threads[count].updates, threads[count].reads); - } - - putchar('\n'); - fflush(stdout); - - /* - * Collect statistics for the data. - */ - for (data_count = 0; data_count < DATASIZE; data_count++) - { - data_updates += data[data_count].updates; - printf ("data %02d: value %d, %d updates\n", - data_count, data[data_count].data, data[data_count].updates); - assert(pthread_rwlock_destroy (&data[data_count].lock) == 0); - } - - printf ("%d thread updates, %d data updates\n", - thread_updates, data_updates); - - __PTW32_FTIME(&currSysTime2); - - printf( "\nstart: %ld/%d, stop: %ld/%d, duration:%ld\n", - (long)currSysTime1.time,currSysTime1.millitm, - (long)currSysTime2.time,currSysTime2.millitm, - ((long)((currSysTime2.time*1000+currSysTime2.millitm) - - (currSysTime1.time*1000+currSysTime1.millitm)))); - - return 0; -} diff --git a/tests/rwlock7_1.c b/tests/rwlock7_1.c deleted file mode 100644 index 4e2ea49..0000000 --- a/tests/rwlock7_1.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * rwlock7_1.c - * - * Hammer on a bunch of rwlocks to test robustness and fairness. - * Printed stats should be roughly even for each thread. - * - * Use CPU affinity to compare against non-affinity rwlock7.c - */ - -#include "test.h" -#include - -#ifdef __GNUC__ -#include -#endif - -#define THREADS 5 -#define DATASIZE 7 -#define ITERATIONS 1000000 - -/* - * Keep statistics for each thread. - */ -typedef struct thread_tag { - int thread_num; - pthread_t thread_id; - cpu_set_t threadCpus; - int updates; - int reads; - int changed; - int seed; -} thread_t; - -/* - * Read-write lock and shared data - */ -typedef struct data_tag { - pthread_rwlock_t lock; - int data; - int updates; -} data_t; - -static thread_t threads[THREADS]; -static data_t data[DATASIZE]; -static cpu_set_t processCpus; -static int cpu_count; - -/* - * Thread start routine that uses read-write locks - */ -void *thread_routine (void *arg) -{ - thread_t *self = (thread_t*)arg; - int iteration; - int element = 0; - int seed = self->seed; - int interval = 1 + rand_r (&seed) % 71; - - /* - * Set each thread to a fixed (different if possible) cpu. - */ - CPU_ZERO(&self->threadCpus); - CPU_SET(self->thread_num%cpu_count, &self->threadCpus); - assert(pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &self->threadCpus) == 0); - - self->changed = 0; - - for (iteration = 0; iteration < ITERATIONS; iteration++) - { - if (iteration % (ITERATIONS / 10) == 0) - { - putchar('.'); - fflush(stdout); - } - /* - * Each "self->interval" iterations, perform an - * update operation (write lock instead of read - * lock). - */ - if ((iteration % interval) == 0) - { - assert(pthread_rwlock_wrlock (&data[element].lock) == 0); - data[element].data = self->thread_num; - data[element].updates++; - self->updates++; - interval = 1 + rand_r (&seed) % 71; - assert(pthread_rwlock_unlock (&data[element].lock) == 0); - } else { - /* - * Look at the current data element to see whether - * the current thread last updated it. Count the - * times, to report later. - */ - assert(pthread_rwlock_rdlock (&data[element].lock) == 0); - - self->reads++; - - if (data[element].data != self->thread_num) - { - self->changed++; - interval = 1 + self->changed % 71; - } - - assert(pthread_rwlock_unlock (&data[element].lock) == 0); - } - - element = (element + 1) % DATASIZE; - - } - - return NULL; -} - -int -main (int argc, char *argv[]) -{ - int count; - int data_count; - int thread_updates = 0; - int data_updates = 0; - int seed = 1; - pthread_t self = pthread_self(); - __PTW32_STRUCT_TIMEB currSysTime1; - __PTW32_STRUCT_TIMEB currSysTime2; - - if (pthread_getaffinity_np(self, sizeof(cpu_set_t), &processCpus) == ENOSYS) - { - printf("pthread_get/set_affinity_np API not supported for this platform: skipping test."); - return 0; - } - - assert(pthread_getaffinity_np(self, sizeof(cpu_set_t), &processCpus) == 0); - assert((cpu_count = CPU_COUNT(&processCpus)) > 0); - printf("CPUs: %d\n", cpu_count); - - /* - * Initialize the shared data. - */ - for (data_count = 0; data_count < DATASIZE; data_count++) - { - data[data_count].data = 0; - data[data_count].updates = 0; - - assert(pthread_rwlock_init (&data[data_count].lock, NULL) == 0); - } - - __PTW32_FTIME(&currSysTime1); - - /* - * Create THREADS threads to access shared data. - */ - for (count = 0; count < THREADS; count++) - { - threads[count].thread_num = count; - threads[count].updates = 0; - threads[count].reads = 0; - threads[count].seed = 1 + rand_r (&seed) % 71; - - assert(pthread_create (&threads[count].thread_id, - NULL, thread_routine, (void*)(size_t)&threads[count]) == 0); - } - - /* - * Wait for all threads to complete, and collect - * statistics. - */ - for (count = 0; count < THREADS; count++) - { - assert(pthread_join (threads[count].thread_id, NULL) == 0); - } - - putchar('\n'); - fflush(stdout); - - for (count = 0; count < THREADS; count++) - { - if (threads[count].changed > 0) - { - printf ("Thread %d found changed elements %d times\n", - count, threads[count].changed); - } - } - - putchar('\n'); - fflush(stdout); - - for (count = 0; count < THREADS; count++) - { - thread_updates += threads[count].updates; - printf ("%02d: seed %d, updates %d, reads %d, cpu %d\n", - count, threads[count].seed, - threads[count].updates, threads[count].reads, - threads[count].thread_num%cpu_count); - } - - putchar('\n'); - fflush(stdout); - - /* - * Collect statistics for the data. - */ - for (data_count = 0; data_count < DATASIZE; data_count++) - { - data_updates += data[data_count].updates; - printf ("data %02d: value %d, %d updates\n", - data_count, data[data_count].data, data[data_count].updates); - assert(pthread_rwlock_destroy (&data[data_count].lock) == 0); - } - - printf ("%d thread updates, %d data updates\n", - thread_updates, data_updates); - - __PTW32_FTIME(&currSysTime2); - - printf( "\nstart: %ld/%d, stop: %ld/%d, duration:%ld\n", - (long)currSysTime1.time,currSysTime1.millitm, - (long)currSysTime2.time,currSysTime2.millitm, - ((long)((currSysTime2.time*1000+currSysTime2.millitm) - - (currSysTime1.time*1000+currSysTime1.millitm)))); - - return 0; -} diff --git a/tests/rwlock8.c b/tests/rwlock8.c deleted file mode 100644 index 301e1ec..0000000 --- a/tests/rwlock8.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * rwlock8.c - * - * Hammer on a bunch of rwlocks to test robustness and fairness. - * Printed stats should be roughly even for each thread. - * - * Yield during each access to exercise lock contention code paths - * more than rwlock7.c does (particularly on uni-processor systems). - */ - -#include "test.h" -#include - -#ifdef __GNUC__ -#include -#endif - -#define THREADS 5 -#define DATASIZE 7 -#define ITERATIONS 100000 - -/* - * Keep statistics for each thread. - */ -typedef struct thread_tag { - int thread_num; - pthread_t thread_id; - int updates; - int reads; - int changed; - int seed; -} thread_t; - -/* - * Read-write lock and shared data - */ -typedef struct data_tag { - pthread_rwlock_t lock; - int data; - int updates; -} data_t; - -static thread_t threads[THREADS]; -static data_t data[DATASIZE]; - -/* - * Thread start routine that uses read-write locks - */ -void *thread_routine (void *arg) -{ - thread_t *self = (thread_t*)arg; - int iteration; - int element = 0; - int seed = self->seed; - int interval = 1 + rand_r (&seed) % 71; - - self->changed = 0; - - for (iteration = 0; iteration < ITERATIONS; iteration++) - { - if (iteration % (ITERATIONS / 10) == 0) - { - putchar('.'); - fflush(stdout); - } - /* - * Each "self->interval" iterations, perform an - * update operation (write lock instead of read - * lock). - */ - if ((iteration % interval) == 0) - { - assert(pthread_rwlock_wrlock (&data[element].lock) == 0); - data[element].data = self->thread_num; - data[element].updates++; - self->updates++; - interval = 1 + rand_r (&seed) % 71; - sched_yield(); - assert(pthread_rwlock_unlock (&data[element].lock) == 0); - } else { - /* - * Look at the current data element to see whether - * the current thread last updated it. Count the - * times, to report later. - */ - assert(pthread_rwlock_rdlock (&data[element].lock) == 0); - - self->reads++; - - if (data[element].data != self->thread_num) - { - self->changed++; - interval = 1 + self->changed % 71; - } - - sched_yield(); - - assert(pthread_rwlock_unlock (&data[element].lock) == 0); - } - - element = (element + 1) % DATASIZE; - - } - - return NULL; -} - -int -main (int argc, char *argv[]) -{ - int count; - int data_count; - int thread_updates = 0; - int data_updates = 0; - int seed = 1; - - __PTW32_STRUCT_TIMEB currSysTime1; - __PTW32_STRUCT_TIMEB currSysTime2; - - /* - * Initialize the shared data. - */ - for (data_count = 0; data_count < DATASIZE; data_count++) - { - data[data_count].data = 0; - data[data_count].updates = 0; - - assert(pthread_rwlock_init (&data[data_count].lock, NULL) == 0); - } - - __PTW32_FTIME(&currSysTime1); - - /* - * Create THREADS threads to access shared data. - */ - for (count = 0; count < THREADS; count++) - { - threads[count].thread_num = count; - threads[count].updates = 0; - threads[count].reads = 0; - threads[count].seed = 1 + rand_r (&seed) % 71; - - assert(pthread_create (&threads[count].thread_id, - NULL, thread_routine, (void*)(size_t)&threads[count]) == 0); - } - - /* - * Wait for all threads to complete, and collect - * statistics. - */ - for (count = 0; count < THREADS; count++) - { - assert(pthread_join (threads[count].thread_id, NULL) == 0); - } - - putchar('\n'); - fflush(stdout); - - for (count = 0; count < THREADS; count++) - { - if (threads[count].changed > 0) - { - printf ("Thread %d found changed elements %d times\n", - count, threads[count].changed); - } - } - - putchar('\n'); - fflush(stdout); - - for (count = 0; count < THREADS; count++) - { - thread_updates += threads[count].updates; - printf ("%02d: seed %d, updates %d, reads %d\n", - count, threads[count].seed, - threads[count].updates, threads[count].reads); - } - - putchar('\n'); - fflush(stdout); - - /* - * Collect statistics for the data. - */ - for (data_count = 0; data_count < DATASIZE; data_count++) - { - data_updates += data[data_count].updates; - printf ("data %02d: value %d, %d updates\n", - data_count, data[data_count].data, data[data_count].updates); - assert(pthread_rwlock_destroy (&data[data_count].lock) == 0); - } - - printf ("%d thread updates, %d data updates\n", - thread_updates, data_updates); - - __PTW32_FTIME(&currSysTime2); - - printf( "\nstart: %ld/%d, stop: %ld/%d, duration:%ld\n", - (long)currSysTime1.time,currSysTime1.millitm, - (long)currSysTime2.time,currSysTime2.millitm, - ((long)((currSysTime2.time*1000+currSysTime2.millitm) - - (currSysTime1.time*1000+currSysTime1.millitm)))); - - return 0; -} diff --git a/tests/rwlock8_1.c b/tests/rwlock8_1.c deleted file mode 100644 index a85f37f..0000000 --- a/tests/rwlock8_1.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * rwlock8.c - * - * Hammer on a bunch of rwlocks to test robustness and fairness. - * Printed stats should be roughly even for each thread. - * - * Yield during each access to exercise lock contention code paths - * more than rwlock7.c does (particularly on uni-processor systems). - * - * Use CPU affinity to compare against non-affinity rwlock8.c - */ - -#include "test.h" -#include - -#ifdef __GNUC__ -#include -#endif - -#define THREADS 5 -#define DATASIZE 7 -#define ITERATIONS 100000 - -/* - * Keep statistics for each thread. - */ -typedef struct thread_tag { - int thread_num; - pthread_t thread_id; - cpu_set_t threadCpus; - int updates; - int reads; - int changed; - int seed; -} thread_t; - -/* - * Read-write lock and shared data - */ -typedef struct data_tag { - pthread_rwlock_t lock; - int data; - int updates; -} data_t; - -static thread_t threads[THREADS]; -static data_t data[DATASIZE]; -static cpu_set_t processCpus; -static int cpu_count; - -/* - * Thread start routine that uses read-write locks - */ -void *thread_routine (void *arg) -{ - thread_t *self = (thread_t*)arg; - int iteration; - int element = 0; - int seed = self->seed; - int interval = 1 + rand_r (&seed) % 71; - - /* - * Set each thread to a fixed (different if possible) cpu. - */ - CPU_ZERO(&self->threadCpus); - CPU_SET(self->thread_num%cpu_count, &self->threadCpus); - assert(pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &self->threadCpus) == 0); - - self->changed = 0; - - for (iteration = 0; iteration < ITERATIONS; iteration++) - { - if (iteration % (ITERATIONS / 10) == 0) - { - putchar('.'); - fflush(stdout); - } - /* - * Each "self->interval" iterations, perform an - * update operation (write lock instead of read - * lock). - */ - if ((iteration % interval) == 0) - { - assert(pthread_rwlock_wrlock (&data[element].lock) == 0); - data[element].data = self->thread_num; - data[element].updates++; - self->updates++; - interval = 1 + rand_r (&seed) % 71; - sched_yield(); - assert(pthread_rwlock_unlock (&data[element].lock) == 0); - } else { - /* - * Look at the current data element to see whether - * the current thread last updated it. Count the - * times, to report later. - */ - assert(pthread_rwlock_rdlock (&data[element].lock) == 0); - - self->reads++; - - if (data[element].data != self->thread_num) - { - self->changed++; - interval = 1 + self->changed % 71; - } - - sched_yield(); - - assert(pthread_rwlock_unlock (&data[element].lock) == 0); - } - - element = (element + 1) % DATASIZE; - - } - - return NULL; -} - -int -main (int argc, char *argv[]) -{ - int count; - int data_count; - int thread_updates = 0; - int data_updates = 0; - int seed = 1; - pthread_t self = pthread_self(); - __PTW32_STRUCT_TIMEB currSysTime1; - __PTW32_STRUCT_TIMEB currSysTime2; - - if (pthread_getaffinity_np(self, sizeof(cpu_set_t), &processCpus) == ENOSYS) - { - printf("pthread_get/set_affinity_np API not supported for this platform: skipping test."); - return 0; - } - - assert(pthread_getaffinity_np(self, sizeof(cpu_set_t), &processCpus) == 0); - assert((cpu_count = CPU_COUNT(&processCpus)) > 0); - printf("CPUs: %d\n", cpu_count); - - /* - * Initialize the shared data. - */ - for (data_count = 0; data_count < DATASIZE; data_count++) - { - data[data_count].data = 0; - data[data_count].updates = 0; - - assert(pthread_rwlock_init (&data[data_count].lock, NULL) == 0); - } - - __PTW32_FTIME(&currSysTime1); - - /* - * Create THREADS threads to access shared data. - */ - for (count = 0; count < THREADS; count++) - { - threads[count].thread_num = count; - threads[count].updates = 0; - threads[count].reads = 0; - threads[count].seed = 1 + rand_r (&seed) % 71; - - assert(pthread_create (&threads[count].thread_id, - NULL, thread_routine, (void*)(size_t)&threads[count]) == 0); - } - - /* - * Wait for all threads to complete, and collect - * statistics. - */ - for (count = 0; count < THREADS; count++) - { - assert(pthread_join (threads[count].thread_id, NULL) == 0); - } - - putchar('\n'); - fflush(stdout); - - for (count = 0; count < THREADS; count++) - { - if (threads[count].changed > 0) - { - printf ("Thread %d found changed elements %d times\n", - count, threads[count].changed); - } - } - - putchar('\n'); - fflush(stdout); - - for (count = 0; count < THREADS; count++) - { - thread_updates += threads[count].updates; - printf ("%02d: seed %d, updates %d, reads %d, cpu %d\n", - count, threads[count].seed, - threads[count].updates, threads[count].reads, - threads[count].thread_num%cpu_count); - } - - putchar('\n'); - fflush(stdout); - - /* - * Collect statistics for the data. - */ - for (data_count = 0; data_count < DATASIZE; data_count++) - { - data_updates += data[data_count].updates; - printf ("data %02d: value %d, %d updates\n", - data_count, data[data_count].data, data[data_count].updates); - assert(pthread_rwlock_destroy (&data[data_count].lock) == 0); - } - - printf ("%d thread updates, %d data updates\n", - thread_updates, data_updates); - - __PTW32_FTIME(&currSysTime2); - - printf( "\nstart: %ld/%d, stop: %ld/%d, duration:%ld\n", - (long)currSysTime1.time,currSysTime1.millitm, - (long)currSysTime2.time,currSysTime2.millitm, - ((long)((currSysTime2.time*1000+currSysTime2.millitm) - - (currSysTime1.time*1000+currSysTime1.millitm)))); - - return 0; -} diff --git a/tests/threestage.c b/tests/threestage.c deleted file mode 100644 index cd607f0..0000000 --- a/tests/threestage.c +++ /dev/null @@ -1,583 +0,0 @@ -/* - This source code is taken directly from examples in the book - Windows System Programming, Edition 4 by Johnson (John) Hart - - Session 6, Chapter 10. ThreeStage.c - - Several required additional header and source files from the - book examples have been included inline to simplify building. - The only modification to the code has been to provide default - values when run without arguments. - - Three-stage Producer Consumer system - Other files required in this project, either directly or - in the form of libraries (DLLs are preferable) - QueueObj.c (inlined here) - Messages.c (inlined here) - - Usage: ThreeStage npc goal [display] - start up "npc" paired producer and consumer threads. - Display messages if "display" is non-zero - Each producer must produce a total of - "goal" messages, where each message is tagged - with the consumer that should receive it - Messages are sent to a "transmitter thread" which performs - additional processing before sending message groups to the - "receiver thread." Finally, the receiver thread sends - the messages to the consumer threads. - - Transmitter: Receive messages one at a time from producers, - create a transmission message of up to "TBLOCK_SIZE" messages - to be sent to the Receiver. (this could be a network xfer - Receiver: Take message blocks sent by the Transmitter - and send the individual messages to the designated consumer - */ - -/* Suppress warning re use of ctime() */ -#define _CRT_SECURE_NO_WARNINGS 1 - -#include "test.h" -#define sleep(i) Sleep(i*1000) -#ifndef max -#define max(a,b) ((a) > (b) ? (a) : (b)) -#endif - -#define DATA_SIZE 256 -typedef struct msg_block_tag { /* Message block */ - pthread_mutex_t mguard; /* Mutex for the message block */ - pthread_cond_t mconsumed; /* Event: Message consumed; */ - /* Produce a new one or stop */ - pthread_cond_t mready; /* Event: Message ready */ - /* - * Note: the mutex and events are not used by some programs, such - * as Program 10-3, 4, 5 (the multi-stage pipeline) as the messages - * are part of a protected queue - */ - volatile unsigned int source; /* Creating producer identity */ - volatile unsigned int destination;/* Identity of receiving thread*/ - - volatile unsigned int f_consumed; - volatile unsigned int f_ready; - volatile unsigned int f_stop; - /* Consumed & ready state flags, stop flag */ - volatile unsigned int sequence; /* Message block sequence number */ - time_t timestamp; - unsigned int checksum; /* Message contents checksum */ - unsigned int data[DATA_SIZE]; /* Message Contents */ -} msg_block_t; - -void message_fill (msg_block_t *, unsigned int, unsigned int, unsigned int); -void message_display (msg_block_t *); - -#define CV_TIMEOUT 5 /* tunable parameter for the CV model */ - - -/* - Definitions of a synchronized, general bounded queue structure. - Queues are implemented as arrays with indices to youngest - and oldest messages, with wrap around. - Each queue also contains a guard mutex and - "not empty" and "not full" condition variables. - Finally, there is a pointer to an array of messages of - arbitrary type - */ - -typedef struct queue_tag { /* General purpose queue */ - pthread_mutex_t q_guard;/* Guard the message block */ - pthread_cond_t q_ne; /* Event: Queue is not empty */ - pthread_cond_t q_nf; /* Event: Queue is not full */ - /* These two events are manual-reset for the broadcast model - * and auto-reset for the signal model */ - volatile unsigned int q_size; /* Queue max size size */ - volatile unsigned int q_first; /* Index of oldest message */ - volatile unsigned int q_last; /* Index of youngest msg */ - volatile unsigned int q_destroyed;/* Q receiver has terminated */ - void * msg_array; /* array of q_size messages */ -} queue_t; - -/* Queue management functions */ -unsigned int q_initialize (queue_t *, unsigned int, unsigned int); -unsigned int q_destroy (queue_t *); -unsigned int q_destroyed (queue_t *); -unsigned int q_empty (queue_t *); -unsigned int q_full (queue_t *); -unsigned int q_get (queue_t *, void *, unsigned int, unsigned int); -unsigned int q_put (queue_t *, void *, unsigned int, unsigned int); -unsigned int q_remove (queue_t *, void *, unsigned int); -unsigned int q_insert (queue_t *, void *, unsigned int); - -#include -#include -#include - -#define DELAY_COUNT 1000 -#define MAX_THREADS 1024 - -/* Queue lengths and blocking factors. These numbers are arbitrary and */ -/* can be adjusted for performance tuning. The current values are */ -/* not well balanced. */ - -#define TBLOCK_SIZE 5 /* Transmitter combines this many messages at at time */ -#define Q_TIMEOUT 2000 /* Transmiter and receiver timeout (ms) waiting for messages */ -//#define Q_TIMEOUT INFINITE -#define MAX_RETRY 5 /* Number of q_get retries before quitting */ -#define P2T_QLEN 10 /* Producer to Transmitter queue length */ -#define T2R_QLEN 4 /* Transmitter to Receiver queue length */ -#define R2C_QLEN 4 /* Receiver to Consumer queue length - there is one - * such queue for each consumer */ - -void * producer (void *); -void * consumer (void *); -void * transmitter (void *); -void * receiver (void *); - - -typedef struct _THARG { - volatile unsigned int thread_number; - volatile unsigned int work_goal; /* used by producers */ - volatile unsigned int work_done; /* Used by producers and consumers */ -} THARG; - - -/* Grouped messages sent by the transmitter to receiver */ -typedef struct T2R_MSG_TYPEag { - volatile unsigned int num_msgs; /* Number of messages contained */ - msg_block_t messages [TBLOCK_SIZE]; -} T2R_MSG_TYPE; - -queue_t p2tq, t2rq, *r2cq_array; - -/* ShutDown, AllProduced are global flags to shut down the system & transmitter */ -static volatile unsigned int ShutDown = 0; -static volatile unsigned int AllProduced = 0; -static unsigned int DisplayMessages = 0; - -int main (int argc, char * argv[]) -{ - unsigned int tstatus = 0, nthread, ithread, goal, thid; - pthread_t *producer_th, *consumer_th, transmitter_th, receiver_th; - THARG *producer_arg, *consumer_arg; - - if (argc < 3) { - nthread = 32; - goal = 1000; - } else { - nthread = atoi(argv[1]); - goal = atoi(argv[2]); - if (argc >= 4) - DisplayMessages = atoi(argv[3]); - } - - srand ((int)time(NULL)); /* Seed the RN generator */ - - if (nthread > MAX_THREADS) { - printf ("Maximum number of producers or consumers is %d.\n", MAX_THREADS); - return 2; - } - producer_th = (pthread_t *) malloc (nthread * sizeof(pthread_t)); - producer_arg = (THARG *) calloc (nthread, sizeof (THARG)); - consumer_th = (pthread_t *) malloc (nthread * sizeof(pthread_t)); - consumer_arg = (THARG *) calloc (nthread, sizeof (THARG)); - - if (producer_th == NULL || producer_arg == NULL - || consumer_th == NULL || consumer_arg == NULL) - perror ("Cannot allocate working memory for threads."); - - q_initialize (&p2tq, sizeof(msg_block_t), P2T_QLEN); - q_initialize (&t2rq, sizeof(T2R_MSG_TYPE), T2R_QLEN); - /* Allocate and initialize Receiver to Consumer queue for each consumer */ - r2cq_array = (queue_t *) calloc (nthread, sizeof(queue_t)); - if (r2cq_array == NULL) perror ("Cannot allocate memory for r2c queues"); - - for (ithread = 0; ithread < nthread; ithread++) { - /* Initialize r2c queue for this consumer thread */ - q_initialize (&r2cq_array[ithread], sizeof(msg_block_t), R2C_QLEN); - /* Fill in the thread arg */ - consumer_arg[ithread].thread_number = ithread; - consumer_arg[ithread].work_goal = goal; - consumer_arg[ithread].work_done = 0; - - tstatus = pthread_create (&consumer_th[ithread], NULL, - consumer, (void *)&consumer_arg[ithread]); - if (tstatus != 0) - perror ("Cannot create consumer thread"); - - producer_arg[ithread].thread_number = ithread; - producer_arg[ithread].work_goal = goal; - producer_arg[ithread].work_done = 0; - tstatus = pthread_create (&producer_th[ithread], NULL, - producer, (void *)&producer_arg[ithread]); - if (tstatus != 0) - perror ("Cannot create producer thread"); - } - - tstatus = pthread_create (&transmitter_th, NULL, transmitter, &thid); - if (tstatus != 0) - perror ("Cannot create tranmitter thread"); - tstatus = pthread_create (&receiver_th, NULL, receiver, &thid); - if (tstatus != 0) - perror ("Cannot create receiver thread"); - - - printf ("BOSS: All threads are running\n"); - /* Wait for the producers to complete */ - /* The implementation allows too many threads for WaitForMultipleObjects */ - /* although you could call WFMO in a loop */ - for (ithread = 0; ithread < nthread; ithread++) { - tstatus = pthread_join (producer_th[ithread], NULL); - if (tstatus != 0) - perror ("Cannot wait for producer thread"); - printf ("BOSS: Producer %d produced %d work units\n", - ithread, producer_arg[ithread].work_done); - } - /* Producers have completed their work. */ - printf ("BOSS: All producers have completed their work.\n"); - AllProduced = 1; - - /* Wait for the consumers to complete */ - for (ithread = 0; ithread < nthread; ithread++) { - tstatus = pthread_join (consumer_th[ithread], NULL); - if (tstatus != 0) - perror ("Cannot wait for consumer thread"); - printf ("BOSS: consumer %d consumed %d work units\n", - ithread, consumer_arg[ithread].work_done); - } - printf ("BOSS: All consumers have completed their work.\n"); - - ShutDown = 1; /* Set a shutdown flag - All messages have been consumed */ - - /* Wait for the transmitter and receiver */ - - tstatus = pthread_join (transmitter_th, NULL); - if (tstatus != 0) - perror ("Failed waiting for transmitter"); - tstatus = pthread_join (receiver_th, NULL); - if (tstatus != 0) - perror ("Failed waiting for receiver"); - - q_destroy (&p2tq); - q_destroy (&t2rq); - for (ithread = 0; ithread < nthread; ithread++) - q_destroy (&r2cq_array[ithread]); - free (r2cq_array); - free (producer_th); - free (consumer_th); - free (producer_arg); - free(consumer_arg); - printf ("System has finished. Shutting down\n"); - return 0; -} - -void * producer (void * arg) -{ - THARG * parg; - unsigned int ithread, tstatus = 0; - msg_block_t msg; - - parg = (THARG *)arg; - ithread = parg->thread_number; - - while (parg->work_done < parg->work_goal && !ShutDown) { - /* Periodically produce work units until the goal is satisfied */ - /* messages receive a source and destination address which are */ - /* the same in this case but could, in general, be different. */ - sleep (rand()/100000000); - message_fill (&msg, ithread, ithread, parg->work_done); - - /* put the message in the queue - Use an infinite timeout to assure - * that the message is inserted, even if consumers are delayed */ - tstatus = q_put (&p2tq, &msg, sizeof(msg), INFINITE); - if (0 == tstatus) { - parg->work_done++; - } - } - - return 0; -} - -void * consumer (void * arg) -{ - THARG * carg; - unsigned int tstatus = 0, ithread, Retries = 0; - msg_block_t msg; - queue_t *pr2cq; - - carg = (THARG *) arg; - ithread = carg->thread_number; - - carg = (THARG *)arg; - pr2cq = &r2cq_array[ithread]; - - while (carg->work_done < carg->work_goal && Retries < MAX_RETRY && !ShutDown) { - /* Receive and display/process messages */ - /* Try to receive the requested number of messages, - * but allow for early system shutdown */ - - tstatus = q_get (pr2cq, &msg, sizeof(msg), Q_TIMEOUT); - if (0 == tstatus) { - if (DisplayMessages > 0) message_display (&msg); - carg->work_done++; - Retries = 0; - } else { - Retries++; - } - } - - return NULL; -} - -void * transmitter (void * arg) -{ - - /* Obtain multiple producer messages, combining into a single */ - /* compound message for the receiver */ - - unsigned int tstatus = 0, im, Retries = 0; - T2R_MSG_TYPE t2r_msg = {0}; - msg_block_t p2t_msg; - - while (!ShutDown && !AllProduced) { - t2r_msg.num_msgs = 0; - /* pack the messages for transmission to the receiver */ - im = 0; - while (im < TBLOCK_SIZE && !ShutDown && Retries < MAX_RETRY && !AllProduced) { - tstatus = q_get (&p2tq, &p2t_msg, sizeof(p2t_msg), Q_TIMEOUT); - if (0 == tstatus) { - memcpy (&t2r_msg.messages[im], &p2t_msg, sizeof(p2t_msg)); - t2r_msg.num_msgs++; - im++; - Retries = 0; - } else { /* Timed out. */ - Retries++; - } - } - tstatus = q_put (&t2rq, &t2r_msg, sizeof(t2r_msg), INFINITE); - if (tstatus != 0) return NULL; - } - return NULL; -} - - -void * receiver (void * arg) -{ - /* Obtain compound messages from the transmitter and unblock them */ - /* and transmit to the designated consumer. */ - - unsigned int tstatus = 0, im, ic, Retries = 0; - T2R_MSG_TYPE t2r_msg; - msg_block_t r2c_msg; - - while (!ShutDown && Retries < MAX_RETRY) { - tstatus = q_get (&t2rq, &t2r_msg, sizeof(t2r_msg), Q_TIMEOUT); - if (tstatus != 0) { /* Timeout - Have the producers shut down? */ - Retries++; - continue; - } - Retries = 0; - /* Distribute the packaged messages to the proper consumer */ - im = 0; - while (im < t2r_msg.num_msgs) { - memcpy (&r2c_msg, &t2r_msg.messages[im], sizeof(r2c_msg)); - ic = r2c_msg.destination; /* Destination consumer */ - tstatus = q_put (&r2cq_array[ic], &r2c_msg, sizeof(r2c_msg), INFINITE); - if (0 == tstatus) im++; - } - } - return NULL; -} - -#if (!defined INFINITE) -#define INFINITE 0xFFFFFFFF -#endif - -/* - Finite bounded queue management functions - q_get, q_put timeouts (max_wait) are in ms - convert to sec, rounding up - */ -unsigned int q_get (queue_t *q, void * msg, unsigned int msize, unsigned int MaxWait) -{ - int tstatus = 0, got_msg = 0, time_inc = (MaxWait + 999) /1000; - struct timespec timeout; - timeout.tv_nsec = 0; - - if (q_destroyed(q)) return 1; - pthread_mutex_lock (&q->q_guard); - while (q_empty (q) && 0 == tstatus) { - if (MaxWait != INFINITE) { - timeout.tv_sec = time(NULL) + time_inc; - tstatus = pthread_cond_timedwait (&q->q_ne, &q->q_guard, &timeout); - } else { - tstatus = pthread_cond_wait (&q->q_ne, &q->q_guard); - } - } - /* remove the message, if any, from the queue */ - if (0 == tstatus && !q_empty (q)) { - q_remove (q, msg, msize); - got_msg = 1; - /* Signal that the queue is not full as we've removed a message */ - pthread_cond_broadcast (&q->q_nf); - } - pthread_mutex_unlock (&q->q_guard); - return (0 == tstatus && got_msg == 1 ? 0 : max(1, tstatus)); /* 0 indicates success */ -} - -unsigned int q_put (queue_t *q, void * msg, unsigned int msize, unsigned int MaxWait) -{ - int tstatus = 0, put_msg = 0, time_inc = (MaxWait + 999) /1000; - struct timespec timeout; - timeout.tv_nsec = 0; - - if (q_destroyed(q)) return 1; - pthread_mutex_lock (&q->q_guard); - while (q_full (q) && 0 == tstatus) { - if (MaxWait != INFINITE) { - timeout.tv_sec = time(NULL) + time_inc; - tstatus = pthread_cond_timedwait (&q->q_nf, &q->q_guard, &timeout); - } else { - tstatus = pthread_cond_wait (&q->q_nf, &q->q_guard); - } - } - /* Insert the message into the queue if there's room */ - if (0 == tstatus && !q_full (q)) { - q_insert (q, msg, msize); - put_msg = 1; - /* Signal that the queue is not empty as we've inserted a message */ - pthread_cond_broadcast (&q->q_ne); - } - pthread_mutex_unlock (&q->q_guard); - return (0 == tstatus && put_msg == 1 ? 0 : max(1, tstatus)); /* 0 indictates success */ -} - -unsigned int q_initialize (queue_t *q, unsigned int msize, unsigned int nmsgs) -{ - /* Initialize queue, including its mutex and events */ - /* Allocate storage for all messages. */ - - q->q_first = q->q_last = 0; - q->q_size = nmsgs; - q->q_destroyed = 0; - - pthread_mutex_init (&q->q_guard, NULL); - pthread_cond_init (&q->q_ne, NULL); - pthread_cond_init (&q->q_nf, NULL); - - if ((q->msg_array = calloc (nmsgs, msize)) == NULL) return 1; - return 0; /* No error */ -} - -unsigned int q_destroy (queue_t *q) -{ - if (q_destroyed(q)) return 1; - /* Free all the resources created by q_initialize */ - pthread_mutex_lock (&q->q_guard); - q->q_destroyed = 1; - free (q->msg_array); - pthread_cond_destroy (&q->q_ne); - pthread_cond_destroy (&q->q_nf); - pthread_mutex_unlock (&q->q_guard); - pthread_mutex_destroy (&q->q_guard); - - return 0; -} - -unsigned int q_destroyed (queue_t *q) -{ - return (q->q_destroyed); -} - -unsigned int q_empty (queue_t *q) -{ - return (q->q_first == q->q_last); -} - -unsigned int q_full (queue_t *q) -{ - return ((q->q_first - q->q_last) == 1 || - (q->q_last == q->q_size-1 && q->q_first == 0)); -} - - -unsigned int q_remove (queue_t *q, void * msg, unsigned int msize) -{ - char *pm; - - pm = (char *)q->msg_array; - /* Remove oldest ("first") message */ - memcpy (msg, pm + (q->q_first * msize), msize); - // Invalidate the message - q->q_first = ((q->q_first + 1) % q->q_size); - return 0; /* no error */ -} - -unsigned int q_insert (queue_t *q, void * msg, unsigned int msize) -{ - char *pm; - - pm = (char *)q->msg_array; - /* Add a new youngest ("last") message */ - if (q_full(q)) return 1; /* Error - Q is full */ - memcpy (pm + (q->q_last * msize), msg, msize); - q->q_last = ((q->q_last + 1) % q->q_size); - - return 0; -} - -unsigned int compute_checksum (void * msg, unsigned int length) -{ - /* Computer an xor checksum on the entire message of "length" - * integers */ - unsigned int i, cs = 0, *pint; - - pint = (unsigned int *) msg; - for (i = 0; i < length; i++) { - cs = (cs ^ *pint); - pint++; - } - return cs; -} - -void message_fill (msg_block_t *mblock, unsigned int src, unsigned int dest, unsigned int seqno) -{ - /* Fill the message buffer, and include checksum and timestamp */ - /* This function is called from the producer thread while it */ - /* owns the message block mutex */ - - unsigned int i; - - mblock->checksum = 0; - for (i = 0; i < DATA_SIZE; i++) { - mblock->data[i] = rand(); - } - mblock->source = src; - mblock->destination = dest; - mblock->sequence = seqno; - mblock->timestamp = time(NULL); - mblock->checksum = compute_checksum (mblock, sizeof(msg_block_t)/sizeof(unsigned int)); - /* printf ("Generated message: %d %d %d %d %x %x\n", - src, dest, seqno, mblock->timestamp, - mblock->data[0], mblock->data[DATA_SIZE-1]); */ - return; -} - -void message_display (msg_block_t *mblock) -{ - /* Display message buffer and timestamp, validate checksum */ - /* This function is called from the consumer thread while it */ - /* owns the message block mutex */ - unsigned int tcheck = 0; - - tcheck = compute_checksum (mblock, sizeof(msg_block_t)/sizeof(unsigned int)); - printf ("\nMessage number %d generated at: %s", - mblock->sequence, ctime (&(mblock->timestamp))); - printf ("Source and destination: %d %d\n", - mblock->source, mblock->destination); - printf ("First and last entries: %x %x\n", - mblock->data[0], mblock->data[DATA_SIZE-1]); - if (tcheck == 0 /*mblock->checksum was 0 when CS first computed */) - printf ("GOOD ->Checksum was validated.\n"); - else - printf ("BAD ->Checksum failed. message was corrupted\n"); - - return; - -} diff --git a/tests/tryentercs.c b/tests/tryentercs.c index 51154e6..15d1420 100644 --- a/tests/tryentercs.c +++ b/tests/tryentercs.c @@ -66,7 +66,7 @@ main() */ _h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL")); _try_enter_critical_section = - (BOOL (PT_STDCALL *)(LPCRITICAL_SECTION)) + (BOOL (WINAPI *)(LPCRITICAL_SECTION)) GetProcAddress(_h_kernel32, (LPCSTR) "TryEnterCriticalSection"); diff --git a/tests/tryentercs2.c b/tests/tryentercs2.c index a747b0f..50c540a 100644 --- a/tests/tryentercs2.c +++ b/tests/tryentercs2.c @@ -65,7 +65,7 @@ main() */ _h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL")); _try_enter_critical_section = - (BOOL (PT_STDCALL *)(LPCRITICAL_SECTION)) + (BOOL (WINAPI *)(LPCRITICAL_SECTION)) GetProcAddress(_h_kernel32, (LPCSTR) "TryEnterCriticalSection");