[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