1 //===-- ManagedStatic.cpp - Static Global wrapper -------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file implements the ManagedStatic class and llvm_shutdown(). 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/Support/ManagedStatic.h" 15 #include "llvm/Config/config.h" 16 #include "llvm/Support/Atomic.h" 17 #include "llvm/Support/MutexGuard.h" 18 #include <cassert> 19 #include <mutex> 20 using namespace llvm; 21 22 static const ManagedStaticBase *StaticList = nullptr; 23 24 // ManagedStatics can get created during execution of static constructors. As a 25 // result, we cannot use a global static std::mutex object for the lock since it 26 // may not have been constructed. Instead, we do a call-once initialization of 27 // a pointer to a mutex. This also means that we must not "initialize" the 28 // mutex with nullptr, otherwise it might get reset to nullptr after being 29 // initialized by std::call_once. 30 static std::once_flag MutexInitializationFlag; 31 static std::recursive_mutex *ManagedStaticMutex; 32 33 namespace { 34 void InitializeManagedStaticMutex() { 35 std::call_once(MutexInitializationFlag, 36 []() { ManagedStaticMutex = new std::recursive_mutex(); }); 37 } 38 } 39 40 void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(), 41 void (*Deleter)(void*)) const { 42 assert(Creator); 43 if (llvm_is_multithreaded()) { 44 InitializeManagedStaticMutex(); 45 46 std::lock_guard<std::recursive_mutex> Lock(*ManagedStaticMutex); 47 if (!Ptr) { 48 void* tmp = Creator(); 49 50 TsanHappensBefore(this); 51 sys::MemoryFence(); 52 53 // This write is racy against the first read in the ManagedStatic 54 // accessors. The race is benign because it does a second read after a 55 // memory fence, at which point it isn't possible to get a partial value. 56 TsanIgnoreWritesBegin(); 57 Ptr = tmp; 58 TsanIgnoreWritesEnd(); 59 DeleterFn = Deleter; 60 61 // Add to list of managed statics. 62 Next = StaticList; 63 StaticList = this; 64 } 65 } else { 66 assert(!Ptr && !DeleterFn && !Next && 67 "Partially initialized ManagedStatic!?"); 68 Ptr = Creator(); 69 DeleterFn = Deleter; 70 71 // Add to list of managed statics. 72 Next = StaticList; 73 StaticList = this; 74 } 75 } 76 77 void ManagedStaticBase::destroy() const { 78 assert(DeleterFn && "ManagedStatic not initialized correctly!"); 79 assert(StaticList == this && 80 "Not destroyed in reverse order of construction?"); 81 // Unlink from list. 82 StaticList = Next; 83 Next = nullptr; 84 85 // Destroy memory. 86 DeleterFn(Ptr); 87 88 // Cleanup. 89 Ptr = nullptr; 90 DeleterFn = nullptr; 91 } 92 93 /// llvm_shutdown - Deallocate and destroy all ManagedStatic variables. 94 void llvm::llvm_shutdown() { 95 InitializeManagedStaticMutex(); 96 std::lock_guard<std::recursive_mutex> Lock(*ManagedStaticMutex); 97 98 while (StaticList) 99 StaticList->destroy(); 100 } 101