1*0b57cec5SDimitry Andric //===-- ManagedStatic.cpp - Static Global wrapper -------------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file implements the ManagedStatic class and llvm_shutdown(). 10*0b57cec5SDimitry Andric // 11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 12*0b57cec5SDimitry Andric 13*0b57cec5SDimitry Andric #include "llvm/Support/ManagedStatic.h" 14*0b57cec5SDimitry Andric #include "llvm/Config/config.h" 15*0b57cec5SDimitry Andric #include "llvm/Support/Threading.h" 16*0b57cec5SDimitry Andric #include <cassert> 17*0b57cec5SDimitry Andric #include <mutex> 18*0b57cec5SDimitry Andric using namespace llvm; 19*0b57cec5SDimitry Andric 20*0b57cec5SDimitry Andric static const ManagedStaticBase *StaticList = nullptr; 21*0b57cec5SDimitry Andric getManagedStaticMutex()22*0b57cec5SDimitry Andricstatic std::recursive_mutex *getManagedStaticMutex() { 23*0b57cec5SDimitry Andric static std::recursive_mutex m; 24*0b57cec5SDimitry Andric return &m; 25*0b57cec5SDimitry Andric } 26*0b57cec5SDimitry Andric RegisterManagedStatic(void * (* Creator)(),void (* Deleter)(void *)) const27*0b57cec5SDimitry Andricvoid ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(), 28*0b57cec5SDimitry Andric void (*Deleter)(void*)) const { 29*0b57cec5SDimitry Andric assert(Creator); 30*0b57cec5SDimitry Andric if (llvm_is_multithreaded()) { 31*0b57cec5SDimitry Andric std::lock_guard<std::recursive_mutex> Lock(*getManagedStaticMutex()); 32*0b57cec5SDimitry Andric 33*0b57cec5SDimitry Andric if (!Ptr.load(std::memory_order_relaxed)) { 34*0b57cec5SDimitry Andric void *Tmp = Creator(); 35*0b57cec5SDimitry Andric 36*0b57cec5SDimitry Andric Ptr.store(Tmp, std::memory_order_release); 37*0b57cec5SDimitry Andric DeleterFn = Deleter; 38*0b57cec5SDimitry Andric 39*0b57cec5SDimitry Andric // Add to list of managed statics. 40*0b57cec5SDimitry Andric Next = StaticList; 41*0b57cec5SDimitry Andric StaticList = this; 42*0b57cec5SDimitry Andric } 43*0b57cec5SDimitry Andric } else { 44*0b57cec5SDimitry Andric assert(!Ptr && !DeleterFn && !Next && 45*0b57cec5SDimitry Andric "Partially initialized ManagedStatic!?"); 46*0b57cec5SDimitry Andric Ptr = Creator(); 47*0b57cec5SDimitry Andric DeleterFn = Deleter; 48*0b57cec5SDimitry Andric 49*0b57cec5SDimitry Andric // Add to list of managed statics. 50*0b57cec5SDimitry Andric Next = StaticList; 51*0b57cec5SDimitry Andric StaticList = this; 52*0b57cec5SDimitry Andric } 53*0b57cec5SDimitry Andric } 54*0b57cec5SDimitry Andric destroy() const55*0b57cec5SDimitry Andricvoid ManagedStaticBase::destroy() const { 56*0b57cec5SDimitry Andric assert(DeleterFn && "ManagedStatic not initialized correctly!"); 57*0b57cec5SDimitry Andric assert(StaticList == this && 58*0b57cec5SDimitry Andric "Not destroyed in reverse order of construction?"); 59*0b57cec5SDimitry Andric // Unlink from list. 60*0b57cec5SDimitry Andric StaticList = Next; 61*0b57cec5SDimitry Andric Next = nullptr; 62*0b57cec5SDimitry Andric 63*0b57cec5SDimitry Andric // Destroy memory. 64*0b57cec5SDimitry Andric DeleterFn(Ptr); 65*0b57cec5SDimitry Andric 66*0b57cec5SDimitry Andric // Cleanup. 67*0b57cec5SDimitry Andric Ptr = nullptr; 68*0b57cec5SDimitry Andric DeleterFn = nullptr; 69*0b57cec5SDimitry Andric } 70*0b57cec5SDimitry Andric 71*0b57cec5SDimitry Andric /// llvm_shutdown - Deallocate and destroy all ManagedStatic variables. 72*0b57cec5SDimitry Andric /// IMPORTANT: it's only safe to call llvm_shutdown() in single thread, 73*0b57cec5SDimitry Andric /// without any other threads executing LLVM APIs. 74*0b57cec5SDimitry Andric /// llvm_shutdown() should be the last use of LLVM APIs. llvm_shutdown()75*0b57cec5SDimitry Andricvoid llvm::llvm_shutdown() { 76*0b57cec5SDimitry Andric while (StaticList) 77*0b57cec5SDimitry Andric StaticList->destroy(); 78*0b57cec5SDimitry Andric } 79*0b57cec5SDimitry Andric