Skip to content

Commit

Permalink
[windows] Implement pthread_mutex for Windows
Browse files Browse the repository at this point in the history
When compiling for Windows, pthread libraries may not be available. For
Win32 applications in which an external implementation of pthread is not
available, we build libcompat with the pthread_mutex.c module, which
provides a simple implementation of pthread_mutex for the Win32 API.
  • Loading branch information
walac committed Jun 11, 2020
1 parent 20bf5f3 commit 1115e47
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 6 deletions.
22 changes: 20 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
15 changes: 15 additions & 0 deletions cmake/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,18 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H 1

/* Define to 1 if you have <windows.h> header file. */
#cmakedefine HAVE_WINDOWS_H 1

/* Define to 1 if you have <synchapi.h> 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

Expand All @@ -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}"

Expand Down
10 changes: 10 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down
24 changes: 23 additions & 1 deletion lib/libcompat.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,31 @@ extern int fpclassify(double d);
#include <sys/wait.h>
#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 <pthread.h>
#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
Expand Down
70 changes: 70 additions & 0 deletions lib/pthread_mutex.c
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
17 changes: 14 additions & 3 deletions src/check_pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*/

#include "../lib/libcompat.h"
#include "config.h"

#include <stdlib.h>
#include <string.h>
Expand All @@ -33,13 +34,20 @@
#include "check_impl.h"
#include "check_pack.h"

#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif

#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
Expand Down Expand Up @@ -348,12 +356,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)
Expand Down
8 changes: 8 additions & 0 deletions tests/cmake_project_usage_test/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down

0 comments on commit 1115e47

Please sign in to comment.