Index: cmake/config-ix.cmake =================================================================== --- cmake/config-ix.cmake +++ cmake/config-ix.cmake @@ -87,6 +87,7 @@ check_library_exists(pthread pthread_getspecific "" HAVE_PTHREAD_GETSPECIFIC) check_library_exists(pthread pthread_rwlock_init "" HAVE_PTHREAD_RWLOCK_INIT) check_library_exists(pthread pthread_mutex_lock "" HAVE_PTHREAD_MUTEX_LOCK) + check_library_exists(pthread pthread_once "" HAVE_PTHREAD_ONCE) else() # this could be Android check_library_exists(c pthread_create "" PTHREAD_IN_LIBC) @@ -94,6 +95,7 @@ check_library_exists(c pthread_getspecific "" HAVE_PTHREAD_GETSPECIFIC) check_library_exists(c pthread_rwlock_init "" HAVE_PTHREAD_RWLOCK_INIT) check_library_exists(c pthread_mutex_lock "" HAVE_PTHREAD_MUTEX_LOCK) + check_library_exists(c pthread_once "" HAVE_PTHREAD_ONCE) endif() endif() check_library_exists(dl dlopen "" HAVE_LIBDL) Index: configure =================================================================== --- configure +++ configure @@ -9625,6 +9625,112 @@ fi + { echo "$as_me:$LINENO: checking for library containing pthread_once" >&5 +echo $ECHO_N "checking for library containing pthread_once... $ECHO_C" >&6; } +if test "${ac_cv_search_pthread_once+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +#include +void foo() {} + +int +main () +{ +pthread_once_t once_control = PTHREAD_ONCE_INIT; +return pthread_once (&once_control, &foo); + ; + return 0; +} +_ACEOF +for ac_lib in '' pthread; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_pthread_once=$ac_res +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if test "${ac_cv_search_pthread_once+set}" = set; then + break +fi +done +if test "${ac_cv_search_pthread_once+set}" = set; then + : +else + ac_cv_search_pthread_once=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_search_pthread_once" >&5 +echo "${ECHO_T}$ac_cv_search_pthread_once" >&6; } +ac_res=$ac_cv_search_pthread_once +if test "$ac_res" != no; then + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_PTHREAD_ONCE 1 +_ACEOF + +fi + fi if test "$LLVM_ENABLE_ZLIB" -eq 1 ; then Index: include/llvm/Config/config.h.cmake =================================================================== --- include/llvm/Config/config.h.cmake +++ include/llvm/Config/config.h.cmake @@ -271,6 +271,9 @@ /* Have pthread_rwlock_init */ #cmakedefine HAVE_PTHREAD_RWLOCK_INIT ${HAVE_PTHREAD_RWLOCK_INIT} +/* Have pthread_once */ +#cmakedefine HAVE_PTHREAD_ONCE ${HAVE_PTHREAD_ONCE} + /* Define to 1 if srand48/lrand48/drand48 exist in */ #cmakedefine HAVE_RAND48 ${HAVE_RAND48} Index: include/llvm/Config/config.h.in =================================================================== --- include/llvm/Config/config.h.in +++ include/llvm/Config/config.h.in @@ -265,6 +265,9 @@ /* Have pthread_rwlock_init */ #undef HAVE_PTHREAD_RWLOCK_INIT +/* Have pthread_once */ +#undef HAVE_PTHREAD_ONCE + /* Define to 1 if srand48/lrand48/drand48 exist in */ #undef HAVE_RAND48 Index: include/llvm/Support/Threading.h =================================================================== --- include/llvm/Support/Threading.h +++ include/llvm/Support/Threading.h @@ -15,6 +15,57 @@ #ifndef LLVM_SUPPORT_THREADING_H #define LLVM_SUPPORT_THREADING_H +#include "llvm/Config/config.h" + +#if __has_include() + +#include + +#define LLVM_CALL_ONCE(function) \ + { \ + static std::once_flag flag; \ + std::call_once(flag, &function); \ + } + +#elif HAVE_PTHREAD_ONCE + +#include + +#define LLVM_CALL_ONCE(function) \ + { \ + static pthread_once_t once_control = PTHREAD_ONCE_INIT; \ + pthread_once(&once_control, &function); \ + } + +#else + +#include "llvm/Support/Atomic.h" +#include "llvm/Support/Valgrind.h" + +#define LLVM_CALL_ONCE(function) \ + { \ + static volatile sys::cas_flag initialized = 0; \ + sys::cas_flag old_val = sys::CompareAndSwap(&initialized, 1, 0); \ + if (old_val == 0) { \ + function(); \ + sys::MemoryFence(); \ + TsanIgnoreWritesBegin(); \ + TsanHappensBefore(&initialized); \ + initialized = 2; \ + TsanIgnoreWritesEnd(); \ + } else { \ + sys::cas_flag tmp = initialized; \ + sys::MemoryFence(); \ + while (tmp != 2) { \ + tmp = initialized; \ + sys::MemoryFence(); \ + } \ + } \ + TsanHappensAfter(&initialized); \ + } + +#endif + namespace llvm { /// Returns true if LLVM is compiled with support for multi-threading, and /// false otherwise. Index: lib/Support/ManagedStatic.cpp =================================================================== --- lib/Support/ManagedStatic.cpp +++ lib/Support/ManagedStatic.cpp @@ -16,16 +16,22 @@ #include "llvm/Support/Atomic.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/MutexGuard.h" +#include "llvm/Support/Threading.h" #include using namespace llvm; static const ManagedStaticBase *StaticList = nullptr; +static sys::Mutex *ManagedStaticMutex = nullptr; -static sys::Mutex& getManagedStaticMutex() { +static void initializeMutex() { + ManagedStaticMutex = new sys::Mutex(); +} + +static sys::Mutex* getManagedStaticMutex() { // We need to use a function local static here, since this can get called // during a static constructor and we need to guarantee that it's initialized // correctly. - static sys::Mutex ManagedStaticMutex; + LLVM_CALL_ONCE(initializeMutex); return ManagedStaticMutex; } @@ -33,7 +39,7 @@ void (*Deleter)(void*)) const { assert(Creator); if (llvm_is_multithreaded()) { - MutexGuard Lock(getManagedStaticMutex()); + MutexGuard Lock(*getManagedStaticMutex()); if (!Ptr) { void* tmp = Creator(); @@ -83,8 +89,13 @@ /// llvm_shutdown - Deallocate and destroy all ManagedStatic variables. void llvm::llvm_shutdown() { - MutexGuard Lock(getManagedStaticMutex()); + { + MutexGuard Lock(*getManagedStaticMutex()); + + while (StaticList) + StaticList->destroy(); + } - while (StaticList) - StaticList->destroy(); + delete ManagedStaticMutex; + ManagedStaticMutex = nullptr; }