diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fd865cb..71893e7a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,8 @@ # cmake_minimum_required(VERSION 3.9 FATAL_ERROR) +include(CheckCCompilerFlag) + # Detect if Check is being used in another build as a subproject # probably with command FetchContent*(). set(THIS_IS_SUBPROJECT FALSE) @@ -112,7 +114,7 @@ if(WIN32) if(MSVC60) set(WINVER 0x0400) else() - set(WINVER 0x0500) + set(WINVER 0x0600) endif() set(_WIN32_WINNT ${WINVER}) endif(WIN32) @@ -162,6 +164,10 @@ ck_check_include_file("strings.h" HAVE_STRINGS_H) ck_check_include_file("sys/time.h" HAVE_SYS_TIME_H) ck_check_include_file("time.h" HAVE_TIME_H) ck_check_include_file("unistd.h" HAVE_UNISTD_H) +ck_check_include_file("pthread.h" HAVE_PTHREAD) + +# check if we have windows.h on native windows environments +ck_check_include_file("windows.h" HAVE_WINDOWS_H) ############################################################################### # Check functions @@ -180,6 +186,10 @@ check_function_exists(strsignal HAVE_DECL_STRSIGNAL) check_function_exists(_getpid HAVE__GETPID) check_function_exists(_strdup HAVE__STRDUP) check_function_exists(alarm HAVE_DECL_ALARM) +if (HAVE_WINDOWS_H) + check_function_exists(InitOnceBeginInitialize HAVE_INIT_ONCE_BEGIN_INITIALIZE) + check_function_exists(InitOnceComplete HAVE_INIT_ONCE_COMPLETE) +endif() if (HAVE_REGEX_H) check_function_exists(regcomp HAVE_REGCOMP) check_function_exists(regexec HAVE_REGEXEC) @@ -234,6 +244,14 @@ if(HAVE_REGEX_H AND HAVE_REGCOMP AND HAVE_REGEXEC) set(ENABLE_REGEX 1) endif() +if (HAVE_PTHREAD) + check_c_compiler_flag("-pthread" HAVE_PTHREADS_FLAG) + if (HAVE_PTHREADS_FLAG) + add_definitions("-pthread") + add_link_options("-pthread") + endif() +endif() + ############################################################################### # Check defines @@ -437,7 +455,7 @@ if(NOT THIS_IS_SUBPROJECT) set(GCOV_LIBS "") endif (CHECK_ENABLE_GCOV) - set(PTHREAD_LIBS "") + set(PTHREAD_LIBS "-pthread") set(LIBS "") if (HAVE_LIBM) diff --git a/cmake/config.h.in b/cmake/config.h.in index 9c2d898a..cea2f3b3 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -303,6 +303,18 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UNISTD_H 1 +/* Define to 1 if you have header file. */ +#cmakedefine HAVE_WINDOWS_H 1 + +/* Define to 1 if you have header file. */ +#cmakedefine HAVE_SYNCHAPI_H 1 + +/* Define to 1 if you have the 'InitOnceBeginInitialize' function. */ +#cmakedefine HAVE_INIT_ONCE_BEGIN_INITIALIZE 1 + +/* Define to 1 if you have the 'InitOnceComplete' function. */ +#cmakedefine HAVE_INIT_ONCE_COMPLETE 1 + /* Define to 1 if the system has the type `unsigned long long'. */ #cmakedefine HAVE_UNSIGNED_LONG_LONG 1 @@ -321,6 +333,9 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the `_strdup' function. */ #cmakedefine HAVE__STRDUP 1 +/* Define 1 if you have pthread support. */ +#cmakedefine HAVE_PTHREAD 1 + /* Version number of Check */ #cmakedefine CHECK_VERSION "${CHECK_MAJOR_VERSION}.${CHECK_MINOR_VERSION}.${CHECK_MICRO_VERSION}" diff --git a/configure.ac b/configure.ac index 6d5dec69..8e458404 100644 --- a/configure.ac +++ b/configure.ac @@ -271,6 +271,16 @@ AM_CONDITIONAL(SUBUNIT, test x"$enable_subunit" != "xfalse") # Check for POSIX regular expressions support. AC_CHECK_HEADERS([regex.h], HAVE_REGEX_H=1, HAVE_REGEX_H=0) +# Check if we have the windows headers for Init Once API +AC_CHECK_HEADERS([windows.h], HAVE_WINDOWS_H=1, HAVE_WINDOWS_H=0) +AC_SUBST(HAVE_WINDOWS_H) + +# Check if we have the One-Time Initialization API +AC_CHECK_FUNCS([InitOnceBeginInitialize], HAVE_INIT_ONCE_BEGIN_INITIALIZE=1, HAVE_INIT_ONCE_BEGIN_INITIALIZE=0) +AC_CHECK_FUNCS([InitOnceComplete], HAVE_INIT_ONCE_COMPLETE=1, HAVE_INIT_ONCE_COMPLETE=0) +AC_SUBST(HAVE_INIT_ONCE_BEGIN_INITIALIZE) +AC_SUBST(HAVE_INIT_ONCE_COMPLETE) + if test "x$HAVE_REGEX_H" = "x1"; then AC_CHECK_FUNCS([regcomp regexec], HAVE_REGEX=1, HAVE_REGEX=0) else diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 97a8dead..38cbc53e 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -67,6 +67,10 @@ if(NOT HAVE_DECL_ALARM) set(SOURCES ${SOURCES} alarm.c) endif(NOT HAVE_DECL_ALARM) +if (NOT HAVE_PTHREAD) + set(SOURCES ${SOURCES} pthread_mutex.c) +endif() + set(HEADERS libcompat.h) add_library(compat STATIC ${SOURCES} ${HEADERS}) diff --git a/lib/libcompat.h b/lib/libcompat.h index 73c2c7ed..816c53bf 100644 --- a/lib/libcompat.h +++ b/lib/libcompat.h @@ -140,9 +140,31 @@ extern int fpclassify(double d); #include #endif +#if defined(HAVE_INIT_ONCE_BEGIN_INITIALIZE) && defined(HAVE_INIT_ONCE_COMPLETE) +#define HAVE_WIN32_INIT_ONCE 1 +#endif + /* declares pthread_create and friends */ -#ifdef HAVE_PTHREAD +#if defined HAVE_PTHREAD #include +#elif defined HAVE_WIN32_INIT_ONCE +typedef void pthread_mutexattr_t; + +typedef struct +{ + INIT_ONCE init; + HANDLE mutex; +} pthread_mutex_t; + +#define PTHREAD_MUTEX_INITIALIZER { \ + INIT_ONCE_STATIC_INIT, \ + NULL, \ +} + +int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr); +int pthread_mutex_destroy(pthread_mutex_t *mutex); +int pthread_mutex_lock(pthread_mutex_t *mutex); +int pthread_mutex_unlock(pthread_mutex_t *mutex); #endif #ifdef HAVE_STDINT_H diff --git a/lib/pthread_mutex.c b/lib/pthread_mutex.c new file mode 100644 index 00000000..abc9c182 --- /dev/null +++ b/lib/pthread_mutex.c @@ -0,0 +1,70 @@ +/* + * Check: a unit test framework for C + * Copyright (C) 2020 Wander Lairson Costa + * + * 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.1 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; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "libcompat.h" + +#ifdef HAVE_WIN32_INIT_ONCE + +static int mutex_init(pthread_mutex_t *mutex) +{ + BOOL pending; + int ret = 0; + + if (!InitOnceBeginInitialize(&mutex->init, 0, &pending, NULL)) + return -1; + + if (pending) + { + mutex->mutex = CreateMutexW(NULL, FALSE, NULL); + if (!mutex->mutex) + ret = -1; + } + + InitOnceComplete(&mutex->init, 0, NULL); + + return ret; +} + +int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr) +{ + InitOnceInitialize(&mutex->init); + return mutex_init(mutex); +} + +int pthread_mutex_destroy(pthread_mutex_t *mutex) +{ + return CloseHandle(mutex->mutex) ? 0 : -1; +} + +int pthread_mutex_lock(pthread_mutex_t *mutex) +{ + if (mutex_init(mutex) != 0) + return -1; + + return WaitForSingleObject(mutex->mutex, INFINITE) != WAIT_OBJECT_0 + ? -1 : 0; +} + +int pthread_mutex_unlock(pthread_mutex_t *mutex) +{ + return ReleaseMutex(mutex->mutex) ? 0 : -1; +} + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 24d5c11c..4a02dbea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -123,6 +123,11 @@ if(NOT HAVE_DECL_ALARM) target_sources(checkShared PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../lib/alarm.c) endif(NOT HAVE_DECL_ALARM) +if(NOT HAVE_PTHREAD) + target_sources(check PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../lib/pthread_mutex.c) + target_sources(checkShared PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../lib/pthread_mutex.c) +endif() + # Include libraries if available if (HAVE_LIBM) target_link_libraries(check PUBLIC m) diff --git a/src/check_pack.c b/src/check_pack.c index be1caf85..f4f4c6a5 100644 --- a/src/check_pack.c +++ b/src/check_pack.c @@ -19,6 +19,7 @@ */ #include "../lib/libcompat.h" +#include "config.h" #include #include @@ -34,12 +35,15 @@ #include "check_pack.h" #ifndef HAVE_PTHREAD -#define pthread_mutex_lock(arg) -#define pthread_mutex_unlock(arg) #define pthread_cleanup_push(f, a) { #define pthread_cleanup_pop(e) } #endif +#ifndef PTHREAD_MUTEX_INITIALIZER +#define pthread_mutex_lock(mutex) +#define pthread_mutex_unlock(mutex) +#endif + /* Maximum size for one message in the message stream. */ static size_t ck_max_msg_size = 0; #ifndef DEFAULT_MAX_MSG_SIZE @@ -348,12 +352,15 @@ static void check_type(int type, const char *file, int line) eprintf("Bad message type arg %d", file, line, type); } -#ifdef HAVE_PTHREAD +#ifdef PTHREAD_MUTEX_INITIALIZER static pthread_mutex_t ck_mutex_lock = PTHREAD_MUTEX_INITIALIZER; + static void ppack_cleanup(void *mutex) { pthread_mutex_unlock((pthread_mutex_t *)mutex); } +#else +#define ppack_cleanup(mutex) #endif void ppack(FILE * fdes, enum ck_msg_type type, CheckMsg * msg) diff --git a/tests/cmake_project_usage_test/src/CMakeLists.txt b/tests/cmake_project_usage_test/src/CMakeLists.txt index ac1a9f7d..46526302 100644 --- a/tests/cmake_project_usage_test/src/CMakeLists.txt +++ b/tests/cmake_project_usage_test/src/CMakeLists.txt @@ -19,6 +19,14 @@ elseif($ENV{INCLUDE_CHECK_WITH} STREQUAL "find_package_config") else() message(FATAL_ERROR "Variable INCLUDE_CHECK_WITH not properly set!") endif() + +include(CheckCCompilerFlag) +check_c_compiler_flag("-pthread" HAVE_PTHREAD) +if (HAVE_PTHREAD) + add_definitions("-pthread") + add_link_options("-pthread") +endif() + add_library(test_suite test_suite.c) target_link_libraries(test_suite PUBLIC Check::check)