Skip to content
Snippets Groups Projects
Commit 911f9b09 authored by Jö Fahlke's avatar Jö Fahlke
Browse files

Merge branch 'feature/fs1544-threadsafe-quadrature'

parents 85b7e8ee c09cf672
Branches
Tags
No related merge requests found
......@@ -197,4 +197,81 @@ check_cxx_source_compiles("
" HAVE_NOEXCEPT_SPECIFIER
)
# find the threading library
find_package(Threads)
set(STDTHREAD_LINK_FLAGS "${CMAKE_THREAD_LIBS_INIT}"
CACHE STRING "Linker flags needed to get working C++11 threads support")
# set linker flags
#
# in all implementations I know it is sufficient to set the linker flags when
# linking the final executable, so this should work. In cmake, this appears
# to only work when building the project however, not for later config tests
# (contrary to CMAKE_CXX_FLAGS). Luckily, later tests don't seem to use any
# threading... (except for our own sanity check)
if(NOT STDTHREAD_LINK_FLAGS STREQUAL "")
#set(vars CMAKE_EXE_LINKER_FLAGS ${CMAKE_CONFIGURATION_TYPES})
# CMAKE_CONFIGURATION_TYPES seems to be empty. Use the configurations from
# adding -std=c++11 above instead.
set(vars CMAKE_EXE_LINKER_FLAGS DEBUG MINSIZEREL RELEASE RELWITHDEBINFO)
string(REPLACE ";" ";CMAKE_EXE_LINKER_FLAGS_" vars "${vars}")
string(TOUPPER "${vars}" vars)
foreach(var ${vars})
if(NOT ${var} STREQUAL "")
set(${var} "${${var}} ${STDTHREAD_LINK_FLAGS}")
endif(NOT ${var} STREQUAL "")
endforeach(var ${vars})
endif(NOT STDTHREAD_LINK_FLAGS STREQUAL "")
include(CheckCXXSourceRuns)
# check that the found configuration works
if(CMAKE_CROSSCOMPILING)
message(WARNING "Crosscompiling, cannot run test program to see whether "
"std::thread works. Assuming that the found configuration does indeed "
"work.")
endif(CMAKE_CROSSCOMPILING)
if(NOT DEFINED STDTHREAD_WORKS)
if(NOT CMAKE_CROSSCOMPILING)
# The value is not in the cache, so run check
cmake_push_check_state()
# tests seem to ignore CMAKE_EXE_LINKER_FLAGS
set(CMAKE_REQUIRED_LIBRARIES "${STDTHREAD_LINK_FLAGS} ${CMAKE_REQUIRED_LIBRARIES}")
check_cxx_source_runs("
#include <thread>
void dummy() {}
int main() {
std::thread t(dummy);
t.join();
}
" STDTHREAD_WORKS)
cmake_pop_check_state()
endif(NOT CMAKE_CROSSCOMPILING)
# put the found value into the cache. Put it there even if we're
# cross-compiling, so the user can find it. Use FORCE:
# check_cxx_source_runs() already puts the value in the cache but without
# documentation; also the "if(NOT DEFINED STDTHREAD_WORKS)" will prevent us
# from overwriting a value set by the user.
set(STDTHREAD_WORKS "${STDTHREAD_WORKS}"
CACHE BOOL "Whether std::thread works." FORCE)
endif(NOT DEFINED STDTHREAD_WORKS)
if(NOT STDTHREAD_WORKS)
# Working C++11 threading support is required for dune. In particular to
# make things like lazyly initialized caches thread safe
# (e.g. QuadratureRules::rule(), which needs std::call_once()). If we don't
# include the correct options during linking, there will be very funny
# errors at runtime, ranging from segfaults to
#
# terminate called after throwing an instance of 'std::system_error'
# what(): Unknown error 18446744073709551615
message(FATAL_ERROR "Your system does not seem to have a working "
"implementation of std::thread. If it does, please set the linker flags "
"required to get std::thread working in the cache variable "
"STDTHREAD_LINK_FLAGS. If you think this test is wrong, set the cache "
"variable STDTHREAD_WORKS.")
endif(NOT STDTHREAD_WORKS)
cmake_pop_check_state()
......@@ -19,6 +19,7 @@ dune_add_library("dunecommon"
parametertreeparser.cc
path.cc
stdstreams.cc
stdthread.cc
ADD_LIBS "${_additional_libs}")
#install headers
......@@ -84,6 +85,7 @@ install(FILES
sllist.hh
static_assert.hh
stdstreams.hh
stdthread.hh
stringutility.hh
timer.hh
tuples.hh
......
......@@ -12,7 +12,8 @@ libcommon_la_SOURCES = \
parametertreeparser.cc \
path.cc \
exceptions.cc \
stdstreams.cc
stdstreams.cc \
stdthread.cc
libcommon_la_LIBADD = $(LAPACK_LIBS) $(BLAS_LIBS) $(LIBS) $(FLIBS)
commonincludedir = $(includedir)/dune/common
......@@ -78,6 +79,7 @@ commoninclude_HEADERS = \
sllist.hh \
static_assert.hh \
stdstreams.hh \
stdthread.hh \
stringutility.hh \
timer.hh \
tuples.hh \
......
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <cstdlib>
#include <iostream>
#include <mutex>
#include <ostream>
#include <dune/common/stdthread.hh>
namespace Dune
{
namespace {
void printCallOnceError(const char *file, int line, const char *function,
const char *msg)
{
if(file)
std::cerr << file << ":" << line << ": ";
std::cerr << "error: ";
if(function)
std::cerr << "(in " << function << "()) ";
std::cerr << "std::call_once() is broken.\n"
<< "\n"
<< msg << std::endl;
}
void setBool(bool *v)
{
*v = true;
}
} // anonymous namespace
void doAssertCallOnce(const char *file, int line, const char *function)
{
std::once_flag once;
bool works = false;
try {
// pass address to works since call_once passes by value
std::call_once(once, setBool, &works);
}
catch(...) {
printCallOnceError(file, line, function,
"std::call_once() throws an exception. This suggests that the program was\n"
"linked without a threading library. Common ways to link to a threading\n"
"libary is to specify one of the following during linking: -pthread, \n"
"-lpthread, or -pthreads. The build-system should have tried various of\n"
"these options, but unfortunately that is only a guess and we cannot verify\n"
"that we found a working configuration until runtime.\n"
"\n"
"Going to rethrow the exception now to give the system library a chance to\n"
"print more information about it, just in case that helps with debugging.\n"
);
throw;
}
if(!works)
{
printCallOnceError(file, line, function,
"std::call_once() never calls the function. This suggests that your\n"
"libctdc++ or your gcc built without threading support (--disable-threads,\n"
"see https://gcc.gnu.org/install/configure.html). This is probably a bug in\n"
"__gthread_once() in /usr/include/c++/4.7/x86_64-linux-gnu/bits/gthr-single.h\n"
"(which should not silently return success without doing anything, but\n"
"apparently does so in some versions).\n"
"\n"
"To fix the issue, either recompile gcc with a working threading\n"
"implementation, or file a bug for gthr-single.h, or file a bug at\n"
"https://dune-project.org/flyspray/ and request a workaround at the dune-side."
);
std::abort();
}
}
} // namespace Dune
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef DUNE_COMMON_STDTHREAD_HH
#define DUNE_COMMON_STDTHREAD_HH
#include <dune/common/nullptr.hh>
#include <dune/common/unused.hh>
namespace Dune
{
// used internally by assertCallOnce for the actual check
void doAssertCallOnce(const char *file, int line, const char *function);
//! \brief Make sure call_once() works and provide a helpful error message
//! otherwise.
/**
* For call_once() to work, certain versions of libstdc++ need to be
* _linked_ with -pthread or similar flags. If that is not the case,
* call_once() will throw an exception. This function checks that
* call_once() can indeed be used, i.e. that it does not throw an exception
* when it should not, and that the code does indeed get executed. If
* call_once() cannot be used, assertCallOnce() aborts the program with a
* helpful error message.
*
* The check is only actually executed the first time assertCallOnce() is
* called.
*
* The arguments \c file and \c line specify the filename and line number
* that should appear in the error message. They are ignored if \c file is
* 0. The argument \c function specifies the name of the function to appear
* in the error message. It is ignored if \c function is 0.
*/
inline void assertCallOnce(const char *file = nullptr, int line = -1,
const char *function = nullptr)
{
// make sure to call this only the first time this function is invoked
static const bool DUNE_UNUSED works
= (doAssertCallOnce(file, line, function), true);
}
//! \brief Make sure call_once() works and provide a helpful error message
//! otherwise.
/**
* This calls assertCallOnce() and automatically provides information about
* the caller in the error message.
*/
#define DUNE_ASSERT_CALL_ONCE() \
::Dune::assertCallOnce(__FILE__, __LINE__, __func__)
} // namespace Dune
#endif // DUNE_COMMON_STDTHREAD_HH
......@@ -11,6 +11,7 @@
/bigunsignedinttest
/bitsetvectortest
/blockbitfieldtest
/calloncetest
/check_fvector_size
/conversiontest
/diagonalmatrixtest
......
......@@ -4,6 +4,7 @@ set(TESTS
arraytest
bigunsignedinttest
bitsetvectortest
calloncetest
check_fvector_size
conversiontest
diagonalmatrixtest
......@@ -65,6 +66,8 @@ add_executable("bigunsignedinttest" bigunsignedinttest.cc)
target_link_libraries("bigunsignedinttest" "dunecommon")
add_executable("bitsetvectortest" bitsetvectortest.cc)
add_executable("calloncetest" calloncetest.cc)
target_link_libraries("calloncetest" "dunecommon")
add_executable("check_fvector_size" check_fvector_size.cc)
add_executable("check_fvector_size_fail1" EXCLUDE_FROM_ALL check_fvector_size_fail.cc)
set_target_properties(check_fvector_size_fail1 PROPERTIES COMPILE_FLAGS "-DDIM=1")
......
......@@ -5,6 +5,7 @@ TESTPROGS = \
arraytest \
bigunsignedinttest \
bitsetvectortest \
calloncetest \
check_fvector_size \
conversiontest \
diagonalmatrixtest \
......@@ -91,6 +92,8 @@ bigunsignedinttest_CPPFLAGS = $(AM_CPPFLAGS)
bitsetvectortest_SOURCES = bitsetvectortest.cc
calloncetest_SOURCES = calloncetest.cc
check_fvector_size_fail1_SOURCES = check_fvector_size_fail.cc
check_fvector_size_fail1_CPPFLAGS = $(AM_CPPFLAGS) -DDIM=1
......
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <dune/common/stdthread.hh>
int main() {
DUNE_ASSERT_CALL_ONCE();
}
......@@ -33,6 +33,13 @@ AC_DEFUN([DUNE_COMMON_CHECKS],
AC_REQUIRE([DUNE_MPI])
AC_REQUIRE([DUNE_SYS_MPROTECT])
AC_REQUIRE([DUNE_STDTHREAD])
AS_IF([test "x$DUNE_STDTHREAD_WORKS" = xno], [
AC_MSG_ERROR([dune-common needs working threading support])
])
DUNE_ADD_MODULE_DEPS([dune-common], [STDTHREAD], [${STDTHREAD_CPPFLAGS}],
[${STDTHREAD_LDFLAGS}], [${STDTHREAD_LIBS}])
dnl check for programs
AC_REQUIRE([AC_PROG_CC])
# add -Wall if the compiler is gcc
......
# Determine flags necessary to compile multithreaded programs
#
# We simply defer to ACX_PTHREAD
AC_DEFUN([DUNE_STDTHREAD],[
AC_REQUIRE([ACX_PTHREAD])
AC_CACHE_CHECK([libraries needed for std::thread],
[dune_cv_stdthread_libs],
[dune_cv_stdthread_libs=$PTHREAD_LIBS])
AC_CACHE_CHECK([linker flags needed for std::thread],
[dune_cv_stdthread_ldflags],
[dune_cv_stdthread_ldflags=$PTHREAD_CFLAGS])
AC_CACHE_CHECK([compiler flags needed for std::thread],
[dune_cv_stdthread_cppflags],
[dune_cv_stdthread_cppflags=$PTHREAD_CFLAGS])
AC_CACHE_CHECK([whether std::thread works],
[dune_cv_stdthread_works],
[
AC_LANG_PUSH([C++])
dune_save_CPPFLAGS=$CPPFLAGS
dune_save_LDFLAGS=$LDFLAGS
dune_save_LIBS=$LIBS
CPPFLAGS="$CPPFLAGS $dune_cv_stdthread_cppflags"
LDFLAGS="$LDFLAGS $dune_cv_stdthread_ldflags"
LIBS="$dune_cv_stdthread_libs $LIBS"
AC_RUN_IFELSE([DUNE_STDTHREAD_TESTPROG],
[dune_cv_stdthread_works=yes],
[dune_cv_stdthread_works=no],
[dune_cv_stdthread_works=unknown])
LIBS=$dune_save_LIBS
LDFLAGS=$dune_save_LDFLAGS
CPPFLAGS=$dune_save_CPPFLAGS
AC_LANG_POP([C++])
])
AS_CASE([$dune_cv_stdthread_works],
[unknown], [AC_MSG_WARN([Cross compiling; cannot check whether std::thread works. I am going to assume that the flags guessed above do work; if not, please adjust the cache variables dune_cv_stdthread_*])
DUNE_STDTHREAD_WORKS=yes],
[DUNE_STDTHREAD_WORKS=$dune_cv_stdthread_works])
AC_SUBST([STDTHREAD_LIBS], ["${dune_cv_stdthread_libs}"])
AC_SUBST([STDTHREAD_LDFLAGS], ["${dune_cv_stdthread_ldflags}"])
AC_SUBST([STDTHREAD_CPPFLAGS], ["${dune_cv_stdthread_cppflags}"])
AM_CONDITIONAL([STDTHREAD], [test "x$DUNE_STDTHREAD_WORKS" = xyes])
])
AC_DEFUN([DUNE_STDTHREAD_TESTPROG], [dnl
AC_LANG_PROGRAM([[
#include <thread>
void f()
{
// do nothing
}
]],
[[
std::thread t(f);
t.join();
]])dnl
])
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment