1f4a2713aSLionel Sambuc //===-- ManagedStatic.cpp - Static Global wrapper -------------------------===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // This file implements the ManagedStatic class and llvm_shutdown().
11f4a2713aSLionel Sambuc //
12f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
13f4a2713aSLionel Sambuc 
14f4a2713aSLionel Sambuc #include "llvm/Support/ManagedStatic.h"
15f4a2713aSLionel Sambuc #include "llvm/Config/config.h"
16f4a2713aSLionel Sambuc #include "llvm/Support/Atomic.h"
17*0a6a1f1dSLionel Sambuc #include "llvm/Support/Mutex.h"
18*0a6a1f1dSLionel Sambuc #include "llvm/Support/MutexGuard.h"
19f4a2713aSLionel Sambuc #include <cassert>
20f4a2713aSLionel Sambuc using namespace llvm;
21f4a2713aSLionel Sambuc 
22*0a6a1f1dSLionel Sambuc static const ManagedStaticBase *StaticList = nullptr;
23*0a6a1f1dSLionel Sambuc 
getManagedStaticMutex()24*0a6a1f1dSLionel Sambuc static sys::Mutex& getManagedStaticMutex() {
25*0a6a1f1dSLionel Sambuc   // We need to use a function local static here, since this can get called
26*0a6a1f1dSLionel Sambuc   // during a static constructor and we need to guarantee that it's initialized
27*0a6a1f1dSLionel Sambuc   // correctly.
28*0a6a1f1dSLionel Sambuc   static sys::Mutex ManagedStaticMutex;
29*0a6a1f1dSLionel Sambuc   return ManagedStaticMutex;
30*0a6a1f1dSLionel Sambuc }
31f4a2713aSLionel Sambuc 
RegisterManagedStatic(void * (* Creator)(),void (* Deleter)(void *)) const32f4a2713aSLionel Sambuc void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(),
33f4a2713aSLionel Sambuc                                               void (*Deleter)(void*)) const {
34*0a6a1f1dSLionel Sambuc   assert(Creator);
35f4a2713aSLionel Sambuc   if (llvm_is_multithreaded()) {
36*0a6a1f1dSLionel Sambuc     MutexGuard Lock(getManagedStaticMutex());
37f4a2713aSLionel Sambuc 
38*0a6a1f1dSLionel Sambuc     if (!Ptr) {
39*0a6a1f1dSLionel Sambuc       void* tmp = Creator();
40f4a2713aSLionel Sambuc 
41f4a2713aSLionel Sambuc       TsanHappensBefore(this);
42f4a2713aSLionel Sambuc       sys::MemoryFence();
43f4a2713aSLionel Sambuc 
44f4a2713aSLionel Sambuc       // This write is racy against the first read in the ManagedStatic
45f4a2713aSLionel Sambuc       // accessors. The race is benign because it does a second read after a
46f4a2713aSLionel Sambuc       // memory fence, at which point it isn't possible to get a partial value.
47f4a2713aSLionel Sambuc       TsanIgnoreWritesBegin();
48f4a2713aSLionel Sambuc       Ptr = tmp;
49f4a2713aSLionel Sambuc       TsanIgnoreWritesEnd();
50f4a2713aSLionel Sambuc       DeleterFn = Deleter;
51f4a2713aSLionel Sambuc 
52f4a2713aSLionel Sambuc       // Add to list of managed statics.
53f4a2713aSLionel Sambuc       Next = StaticList;
54f4a2713aSLionel Sambuc       StaticList = this;
55f4a2713aSLionel Sambuc     }
56f4a2713aSLionel Sambuc   } else {
57*0a6a1f1dSLionel Sambuc     assert(!Ptr && !DeleterFn && !Next &&
58f4a2713aSLionel Sambuc            "Partially initialized ManagedStatic!?");
59*0a6a1f1dSLionel Sambuc     Ptr = Creator();
60f4a2713aSLionel Sambuc     DeleterFn = Deleter;
61f4a2713aSLionel Sambuc 
62f4a2713aSLionel Sambuc     // Add to list of managed statics.
63f4a2713aSLionel Sambuc     Next = StaticList;
64f4a2713aSLionel Sambuc     StaticList = this;
65f4a2713aSLionel Sambuc   }
66f4a2713aSLionel Sambuc }
67f4a2713aSLionel Sambuc 
destroy() const68f4a2713aSLionel Sambuc void ManagedStaticBase::destroy() const {
69f4a2713aSLionel Sambuc   assert(DeleterFn && "ManagedStatic not initialized correctly!");
70f4a2713aSLionel Sambuc   assert(StaticList == this &&
71f4a2713aSLionel Sambuc          "Not destroyed in reverse order of construction?");
72f4a2713aSLionel Sambuc   // Unlink from list.
73f4a2713aSLionel Sambuc   StaticList = Next;
74*0a6a1f1dSLionel Sambuc   Next = nullptr;
75f4a2713aSLionel Sambuc 
76f4a2713aSLionel Sambuc   // Destroy memory.
77f4a2713aSLionel Sambuc   DeleterFn(Ptr);
78f4a2713aSLionel Sambuc 
79f4a2713aSLionel Sambuc   // Cleanup.
80*0a6a1f1dSLionel Sambuc   Ptr = nullptr;
81*0a6a1f1dSLionel Sambuc   DeleterFn = nullptr;
82f4a2713aSLionel Sambuc }
83f4a2713aSLionel Sambuc 
84f4a2713aSLionel Sambuc /// llvm_shutdown - Deallocate and destroy all ManagedStatic variables.
llvm_shutdown()85f4a2713aSLionel Sambuc void llvm::llvm_shutdown() {
86*0a6a1f1dSLionel Sambuc   MutexGuard Lock(getManagedStaticMutex());
87*0a6a1f1dSLionel Sambuc 
88f4a2713aSLionel Sambuc   while (StaticList)
89f4a2713aSLionel Sambuc     StaticList->destroy();
90f4a2713aSLionel Sambuc }
91