[PATCH] Removing the static initializer in ManagedStatic.cpp by using llvm_call_once to initialize the ManagedStatic mutex.
Aaron Ballman
aaron.ballman at gmail.com
Thu Oct 23 06:50:39 PDT 2014
On Wed, Oct 22, 2014 at 7:59 PM, Chris Bieneman <beanz at apple.com> wrote:
> Hi chandlerc, rnk, aaron.ballman, chapuni,
>
> This patch adds an llvm_call_once which is a wrapper around std::call_once on platforms where it is available and devoid of bugs. The patch also migrates the ManagedStatic mutex to be allocated using llvm_call_once.
>
> These changes are philosophically equivalent to the changes added in r219638, which were reverted due to a hang on Win32 which was the result of a bug in the Windows implementation of std::call_once.
>
> http://reviews.llvm.org/D5922
> Index: include/llvm/Support/Threading.h
> ===================================================================
> --- include/llvm/Support/Threading.h
> +++ include/llvm/Support/Threading.h
> @@ -15,6 +15,15 @@
> #ifndef LLVM_SUPPORT_THREADING_H
> #define LLVM_SUPPORT_THREADING_H
>
> +#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
> +
> +#if defined(LLVM_ON_UNIX)
> +#include <mutex>
> +#else
> +#include "llvm/Support/Atomic.h"
> +#include "llvm/Support/Valgrind.h"
> +#endif
> +
> namespace llvm {
> /// Returns true if LLVM is compiled with support for multi-threading, and
> /// false otherwise.
> @@ -33,6 +42,48 @@
> /// the thread stack.
> void llvm_execute_on_thread(void (*UserFn)(void*), void *UserData,
> unsigned RequestedStackSize = 0);
> +
> +/// \brief Execute the function specified as a template parameter once.
> +///
> +/// Calls \p UserFn once ever.
Can drop the "ever."
> The call uniqueness is based on the address of
> +/// the function passed in via the template arguement.
"argument" instead of "arguement."
> This means no matter how
> +/// many times you call llvm_call_once<foo>() in the same or different
> +/// locations, foo will only be called once.
> +///
> +/// Typical usage:
> +/// \code
> +/// void foo() {...};
> +/// ...
> +/// llvm_call_once<foo>();
> +/// \endcode
> +///
> +/// \tparam UserFn Function to call once.
> +template <void (*UserFn)(void)> void llvm_call_once() {
> +#if defined(LLVM_ON_UNIX)
> + static std::once_flag flag;
> + std::call_once(flag, UserFn);
> +#else
> + // Due to a bug in Windows 7's C++ runtime std::call_once cannot be called
> + // during a static initializer. To workaround this the hand rolled solution
> + // below uses thread primitives to implement call_once semantics.
> + // Visual Studio bug id #811192.
Formatting of the comments.
> + static volatile sys::cas_flag initialized = 0;
> + sys::cas_flag old_val = sys::CompareAndSwap(&initialized, 1, 0);
> + if (old_val == 0) {
> + UserFn();
> + sys::MemoryFence();
> + initialized = 2;
> + }
> + else {
> + sys::cas_flag tmp = initialized;
> + sys::MemoryFence();
> + while (tmp != 2) {
> + tmp = initialized;
> + sys::MemoryFence();
> + }
> + }
Is there a way we can use the one-time initialization functionality
built into Windows instead of hand-rolling our own logic?
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363808(v=vs.85).aspx
> +#endif
> +}
> }
>
> #endif
> Index: lib/Support/ManagedStatic.cpp
> ===================================================================
> --- lib/Support/ManagedStatic.cpp
> +++ lib/Support/ManagedStatic.cpp
> @@ -16,24 +16,30 @@
> #include "llvm/Support/Atomic.h"
> #include "llvm/Support/Mutex.h"
> #include "llvm/Support/MutexGuard.h"
> +#include "llvm/Support/Threading.h"
> #include <cassert>
> 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;
> }
>
> void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(),
> void (*Deleter)(void*)) const {
> assert(Creator);
> if (llvm_is_multithreaded()) {
> - MutexGuard Lock(getManagedStaticMutex());
> + MutexGuard Lock(*getManagedStaticMutex());
>
> if (!Ptr) {
> void* tmp = Creator();
> @@ -83,7 +89,7 @@
>
> /// llvm_shutdown - Deallocate and destroy all ManagedStatic variables.
> void llvm::llvm_shutdown() {
> - MutexGuard Lock(getManagedStaticMutex());
> + MutexGuard Lock(*getManagedStaticMutex());
>
> while (StaticList)
> StaticList->destroy();
>
~Aaron
More information about the llvm-commits
mailing list