1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-22 04:22:57 +02:00
llvm-mirror/lib/Support/ManagedStatic.cpp
Chandler Carruth d7aa55c96c [LPM] Reinstate r271781 which reinstated r271652 to replace the
CALL_ONCE_... macro in the legacy pass manager with the new
llvm::call_once facility.

Nothing changed sicne the last attempt in r271781 which I reverted in
r271788. At least one of the failures I saw was spurious, and I want to
make sure the other failures are real before I work around them -- they
appeared to only effect ppc64le and ppc64be.

Original commit message of r271781:
----
[LPM] Reinstate r271652 to replace the CALL_ONCE_... macro in the legacy
pass manager with the new llvm::call_once facility.

This reverts commit r271657 and re-applies r271652 with a fix to
actually work with arguments. In the original version, we just ended up
directly calling std::call_once via ADL because of the std::once_flag
argument. The llvm::call_once never worked with arguments. Now,
llvm::call_once is a variadic template that perfectly forwards
everything. As a part of this it had to move to the header and we use
a generic functor rather than an explict function pointer. It would be
nice to use std::invoke here but we don't have it yet. That means
pointer to members won't work here, but that seems a tolerable
compromise.

I've also tested this by forcing the fallback path, so hopefully it
sticks this time.
----

Original commit message of r271652:
----
[LPM] Replace the CALL_ONCE_... macro in the legacy pass manager with
the new llvm::call_once facility.

This facility matches the standard APIs and when the platform supports
it actually directly uses the standard provided functionality. This is
both more efficient on some platforms and much more TSan friendly.

The only remaining user of the cas_flag and home-rolled atomics is the
fallback implementation of call_once. I have a patch that removes them
entirely, but it needs a Windows patch to land first.

This alone substantially cleans up the macros for the legacy pass
manager, and should subsume some of the work Mehdi was doing to clear
the path for TSan testing of ThinLTO, a really important step to have
reliable upstream testing of ThinLTO in all forms.
----

llvm-svn: 271800
2016-06-04 19:57:55 +00:00

98 lines
2.8 KiB
C++

//===-- ManagedStatic.cpp - Static Global wrapper -------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the ManagedStatic class and llvm_shutdown().
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Config/config.h"
#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;
LLVM_DEFINE_ONCE_FLAG(mutex_init_flag);
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.
llvm::call_once(mutex_init_flag, initializeMutex);
return ManagedStaticMutex;
}
void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(),
void (*Deleter)(void*)) const {
assert(Creator);
if (llvm_is_multithreaded()) {
MutexGuard Lock(*getManagedStaticMutex());
if (!Ptr) {
void* tmp = Creator();
TsanHappensBefore(this);
sys::MemoryFence();
// This write is racy against the first read in the ManagedStatic
// accessors. The race is benign because it does a second read after a
// memory fence, at which point it isn't possible to get a partial value.
TsanIgnoreWritesBegin();
Ptr = tmp;
TsanIgnoreWritesEnd();
DeleterFn = Deleter;
// Add to list of managed statics.
Next = StaticList;
StaticList = this;
}
} else {
assert(!Ptr && !DeleterFn && !Next &&
"Partially initialized ManagedStatic!?");
Ptr = Creator();
DeleterFn = Deleter;
// Add to list of managed statics.
Next = StaticList;
StaticList = this;
}
}
void ManagedStaticBase::destroy() const {
assert(DeleterFn && "ManagedStatic not initialized correctly!");
assert(StaticList == this &&
"Not destroyed in reverse order of construction?");
// Unlink from list.
StaticList = Next;
Next = nullptr;
// Destroy memory.
DeleterFn(Ptr);
// Cleanup.
Ptr = nullptr;
DeleterFn = nullptr;
}
/// llvm_shutdown - Deallocate and destroy all ManagedStatic variables.
void llvm::llvm_shutdown() {
MutexGuard Lock(*getManagedStaticMutex());
while (StaticList)
StaticList->destroy();
}