Skip to content

Commit 108515e

Browse files
committed
[ManagedStatic] Reimplement double-checked locking with std::atomic.
This gets rid of the memory fence in the hot path (dereferencing the ManagedStatic), trading for an extra mutex lock in the cold path (when the ManagedStatic was uninitialized). Since this only happens on the first accesses it shouldn't matter much. On strict architectures like x86 this removes any atomic instructions from the hot path. Also remove the tsan annotations, tsan knows how standard atomics work so they should be unnecessary now. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@274131 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 99b4877 commit 108515e

File tree

2 files changed

+17
-40
lines changed

2 files changed

+17
-40
lines changed

include/llvm/Support/ManagedStatic.h

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
#ifndef LLVM_SUPPORT_MANAGEDSTATIC_H
1515
#define LLVM_SUPPORT_MANAGEDSTATIC_H
1616

17-
#include "llvm/Support/Atomic.h"
1817
#include "llvm/Support/Compiler.h"
19-
#include "llvm/Support/Threading.h"
18+
#include <atomic>
19+
#include <cstddef>
2020

2121
namespace llvm {
2222

@@ -41,7 +41,7 @@ class ManagedStaticBase {
4141
protected:
4242
// This should only be used as a static variable, which guarantees that this
4343
// will be zero initialized.
44-
mutable void *Ptr;
44+
mutable std::atomic<void *> Ptr;
4545
mutable void (*DeleterFn)(void*);
4646
mutable const ManagedStaticBase *Next;
4747

@@ -61,40 +61,26 @@ class ManagedStaticBase {
6161
template<class C>
6262
class ManagedStatic : public ManagedStaticBase {
6363
public:
64-
6564
// Accessors.
6665
C &operator*() {
67-
void* tmp = Ptr;
68-
if (llvm_is_multithreaded()) sys::MemoryFence();
69-
if (!tmp) RegisterManagedStatic(object_creator<C>, object_deleter<C>::call);
70-
TsanHappensAfter(this);
66+
void *Tmp = Ptr.load(std::memory_order_acquire);
67+
if (!Tmp)
68+
RegisterManagedStatic(object_creator<C>, object_deleter<C>::call);
7169

72-
return *static_cast<C*>(Ptr);
70+
return *static_cast<C *>(Ptr.load(std::memory_order_relaxed));
7371
}
74-
C *operator->() {
75-
void* tmp = Ptr;
76-
if (llvm_is_multithreaded()) sys::MemoryFence();
77-
if (!tmp) RegisterManagedStatic(object_creator<C>, object_deleter<C>::call);
78-
TsanHappensAfter(this);
7972

80-
return static_cast<C*>(Ptr);
81-
}
73+
C *operator->() { return &**this; }
74+
8275
const C &operator*() const {
83-
void* tmp = Ptr;
84-
if (llvm_is_multithreaded()) sys::MemoryFence();
85-
if (!tmp) RegisterManagedStatic(object_creator<C>, object_deleter<C>::call);
86-
TsanHappensAfter(this);
76+
void *Tmp = Ptr.load(std::memory_order_acquire);
77+
if (!Tmp)
78+
RegisterManagedStatic(object_creator<C>, object_deleter<C>::call);
8779

88-
return *static_cast<C*>(Ptr);
80+
return *static_cast<C *>(Ptr.load(std::memory_order_relaxed));
8981
}
90-
const C *operator->() const {
91-
void* tmp = Ptr;
92-
if (llvm_is_multithreaded()) sys::MemoryFence();
93-
if (!tmp) RegisterManagedStatic(object_creator<C>, object_deleter<C>::call);
94-
TsanHappensAfter(this);
9582

96-
return static_cast<C*>(Ptr);
97-
}
83+
const C *operator->() const { return &**this; }
9884
};
9985

10086
/// llvm_shutdown - Deallocate and destroy all ManagedStatic variables.

lib/Support/ManagedStatic.cpp

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
#include "llvm/Support/ManagedStatic.h"
1515
#include "llvm/Config/config.h"
16-
#include "llvm/Support/Atomic.h"
1716
#include "llvm/Support/Mutex.h"
1817
#include "llvm/Support/MutexGuard.h"
1918
#include "llvm/Support/Threading.h"
@@ -42,18 +41,10 @@ void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(),
4241
if (llvm_is_multithreaded()) {
4342
MutexGuard Lock(*getManagedStaticMutex());
4443

45-
if (!Ptr) {
46-
void* tmp = Creator();
44+
if (!Ptr.load(std::memory_order_relaxed)) {
45+
void *Tmp = Creator();
4746

48-
TsanHappensBefore(this);
49-
sys::MemoryFence();
50-
51-
// This write is racy against the first read in the ManagedStatic
52-
// accessors. The race is benign because it does a second read after a
53-
// memory fence, at which point it isn't possible to get a partial value.
54-
TsanIgnoreWritesBegin();
55-
Ptr = tmp;
56-
TsanIgnoreWritesEnd();
47+
Ptr.store(Tmp, std::memory_order_release);
5748
DeleterFn = Deleter;
5849

5950
// Add to list of managed statics.

0 commit comments

Comments
 (0)