llvm.org GIT mirror llvm / 8290382
This is yet another attempt to re-instate r220932 as discussed in D19271. Previous attempt was broken by NetBSD, so in this version I've made the fallback path generic rather than Windows specific and sent both Windows and NetBSD to it. I've also re-formatted the code some, and used an exact clone of the code in PassSupport.h for doing manual call-once using our atomics rather than rolling a new one. If this sticks, we can replace the fallback path for Windows with a Windows-specific implementation that is more reliable. Original commit message: 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. Differential Revision: http://reviews.llvm.org/D5922 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@271558 91177308-0d34-0410-b5e6-96231b3b80d8 Chandler Carruth 4 years ago
3 changed file(s) with 90 addition(s) and 4 deletion(s). Raw diff Collapse all Expand all
1313
1414 #ifndef LLVM_SUPPORT_THREADING_H
1515 #define LLVM_SUPPORT_THREADING_H
16
17 #include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
18 #include // So we can check the C++ standard lib macros.
19
20 // We use std::call_once on all Unix platforms except for NetBSD with
21 // libstdc++. That platform has a bug they are working to fix, and they'll
22 // remove the NetBSD checks once fixed.
23 #if defined(LLVM_ON_UNIX) && !(defined(__NetBSD__) && !defined(_LIBCPP_VERSION))
24 #define LLVM_THREADING_USE_STD_CALL_ONCE 1
25 #else
26 #define LLVM_THREADING_USE_STD_CALL_ONCE 0
27 #endif
28
29 #if LLVM_THREADING_USE_STD_CALL_ONCE
30 #include
31 #else
32 #include "llvm/Support/Atomic.h"
33 #endif
1634
1735 namespace llvm {
1836 /// Returns true if LLVM is compiled with support for multi-threading, and
3351 /// the thread stack.
3452 void llvm_execute_on_thread(void (*UserFn)(void*), void *UserData,
3553 unsigned RequestedStackSize = 0);
54
55 #if LLVM_THREADING_USE_STD_CALL_ONCE
56
57 typedef std::once_flag once_flag;
58
59 /// This macro is the only way you should define your once flag for LLVM's
60 /// call_once.
61 #define LLVM_DEFINE_ONCE_FLAG(flag) static once_flag flag
62
63 #else
64
65 enum InitStatus { Uninitialized = 0, Wait = 1, Done = 2 };
66 typedef volatile sys::cas_flag once_flag;
67
68 /// This macro is the only way you should define your once flag for LLVM's
69 /// call_once.
70 #define LLVM_DEFINE_ONCE_FLAG(flag) static once_flag flag = Uninitialized
71
72 #endif
73
74 /// \brief Execute the function specified as a parameter once.
75 ///
76 /// Typical usage:
77 /// \code
78 /// void foo() {...};
79 /// ...
80 /// LLVM_DEFINE_ONCE_FLAG(flag);
81 /// call_once(flag, foo);
82 /// \endcode
83 ///
84 /// \param flag Flag used for tracking whether or not this has run.
85 /// \param UserFn Function to call once.
86 void call_once(once_flag &flag, void (*UserFn)(void));
3687 }
3788
3889 #endif
1515 #include "llvm/Support/Atomic.h"
1616 #include "llvm/Support/Mutex.h"
1717 #include "llvm/Support/MutexGuard.h"
18 #include "llvm/Support/Threading.h"
1819 #include
1920 using namespace llvm;
2021
2122 static const ManagedStaticBase *StaticList = nullptr;
23 static sys::Mutex *ManagedStaticMutex = nullptr;
24 LLVM_DEFINE_ONCE_FLAG(mutex_init_flag);
2225
23 static sys::Mutex& getManagedStaticMutex() {
26 static void initializeMutex() {
27 ManagedStaticMutex = new sys::Mutex();
28 }
29
30 static sys::Mutex* getManagedStaticMutex() {
2431 // We need to use a function local static here, since this can get called
2532 // during a static constructor and we need to guarantee that it's initialized
2633 // correctly.
27 static sys::Mutex ManagedStaticMutex;
34 call_once(mutex_init_flag, initializeMutex);
2835 return ManagedStaticMutex;
2936 }
3037
3239 void (*Deleter)(void*)) const {
3340 assert(Creator);
3441 if (llvm_is_multithreaded()) {
35 MutexGuard Lock(getManagedStaticMutex());
42 MutexGuard Lock(*getManagedStaticMutex());
3643
3744 if (!Ptr) {
3845 void* tmp = Creator();
8289
8390 /// llvm_shutdown - Deallocate and destroy all ManagedStatic variables.
8491 void llvm::llvm_shutdown() {
85 MutexGuard Lock(getManagedStaticMutex());
92 MutexGuard Lock(*getManagedStaticMutex());
8693
8794 while (StaticList)
8895 StaticList->destroy();
1515 #include "llvm/Config/config.h"
1616 #include "llvm/Support/Atomic.h"
1717 #include "llvm/Support/Mutex.h"
18 #include "llvm/Support/thread.h"
1819 #include
1920
2021 using namespace llvm;
109110 }
110111
111112 #endif
113
114 void llvm::call_once(once_flag &flag, void (*fptr)(void)) {
115 #if LLVM_THREADING_USE_STD_CALL_ONCE
116 std::call_once(flag, fptr);
117 #else
118 // For other platforms we use a generic (if brittle) version based on our
119 // atomics.
120 sys::cas_flag old_val = sys::CompareAndSwap(&flag, Wait, Uninitialized);
121 if (old_val == Uninitialized) {
122 fptr();
123 sys::MemoryFence();
124 TsanIgnoreWritesBegin();
125 TsanHappensBefore(&flag);
126 flag = Done;
127 TsanIgnoreWritesEnd();
128 } else {
129 // Wait until any thread doing the call has finished.
130 sys::cas_flag tmp = flag;
131 sys::MemoryFence();
132 while (tmp != Done) {
133 tmp = flag;
134 sys::MemoryFence();
135 }
136 }
137 TsanHappensAfter(&flag);
138 #endif
139 }