nhaehnle created this revision.
Herald added a reviewer: deadalnix.
Herald added subscribers: bzcheeseman, ayermolo, sdasgup3, wenzhicui, wrengr, 
dcaballe, cota, teijeong, rdzhabarov, tatianashp, msifontes, jurahul, Kayjukh, 
grosul1, jvesely, Joonsoo, liufengdb, aartbik, mgester, arpith-jacob, 
antiagainst, shauheen, rriddle, mehdi_amini, mstorsjo, hiraditya, mgorny.
Herald added a reviewer: bollu.
Herald added a reviewer: MaskRay.
Herald added a reviewer: rafauler.
Herald added a reviewer: Amir.
Herald added a reviewer: maksfb.
Herald added a project: All.
nhaehnle requested review of this revision.
Herald added subscribers: lldb-commits, cfe-commits, yota9, StephenFan, 
stephenneuendorffer, nicolasvasilache.
Herald added projects: clang, LLDB, MLIR, LLVM.

This allows LLVM to be safely loaded and unloaded as a shared library
without leaking memory:

Consider the scenario where shared library Foo links against LLVM as
a shared library, and Foo may be loaded and unloaded multiple times
in the same process. Should Foo call llvm_shutdown or not? If it does
not, and LLVM is also loaded and unloaded multiple times, then
memory is leaked. If it does call llvm_shutdown and LLVM *isn't*
also unloaded, the state of LLVM's global statics is corrupted because
while the ManagedStatics may be re-initialized, *other* global
constructors aren't re-run.

Keep in mind that Foo itself may use ManagedStatic. If Foo is unloaded
but LLVM isn't, those statics should be destroyed.

The safe solution is to skip llvm_shutdown() altogether and destroy
managed statics from their destructor.

LLD relies on being able to call _exit() and still get some side-effects
of managed static destructors. We make this expectation much more
explicit.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D128166

Files:
  bolt/tools/driver/llvm-bolt.cpp
  bolt/tools/merge-fdata/merge-fdata.cpp
  clang/include/clang/Frontend/CompilerInstance.h
  clang/tools/clang-repl/ClangRepl.cpp
  clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp
  clang/unittests/Interpreter/InterpreterTest.cpp
  clang/utils/TableGen/TableGen.cpp
  libclc/utils/prepare-builtins.cpp
  lld/Common/ErrorHandler.cpp
  lldb/tools/driver/Driver.cpp
  lldb/tools/lldb-test/lldb-test.cpp
  lldb/unittests/Utility/LogTest.cpp
  lldb/utils/TableGen/LLDBTableGen.cpp
  llvm/docs/ProgrammersManual.rst
  llvm/examples/BrainF/BrainFDriver.cpp
  llvm/examples/HowToUseJIT/HowToUseJIT.cpp
  llvm/include/llvm-c/Core.h
  llvm/include/llvm/ADT/Statistic.h
  llvm/include/llvm/PassRegistry.h
  llvm/include/llvm/Support/DynamicLibrary.h
  llvm/include/llvm/Support/FastShutdown.h
  llvm/include/llvm/Support/InitLLVM.h
  llvm/include/llvm/Support/ManagedStatic.h
  llvm/lib/IR/Core.cpp
  llvm/lib/IR/Pass.cpp
  llvm/lib/IR/PassRegistry.cpp
  llvm/lib/Support/CMakeLists.txt
  llvm/lib/Support/FastShutdown.cpp
  llvm/lib/Support/InitLLVM.cpp
  llvm/lib/Support/ManagedStatic.cpp
  llvm/lib/Support/Parallel.cpp
  llvm/lib/Support/Statistic.cpp
  llvm/lib/Support/Unix/DynamicLibrary.inc
  llvm/lib/Support/Unix/Signals.inc
  llvm/lib/Support/Windows/DynamicLibrary.inc
  llvm/tools/gold/gold-plugin.cpp
  llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
  llvm/unittests/ExecutionEngine/ExecutionEngineTest.cpp
  llvm/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp
  llvm/utils/KillTheDoctor/KillTheDoctor.cpp
  mlir/tools/mlir-vulkan-runner/mlir-vulkan-runner.cpp
  polly/lib/External/isl/interface/extract_interface.cc

Index: polly/lib/External/isl/interface/extract_interface.cc
===================================================================
--- polly/lib/External/isl/interface/extract_interface.cc
+++ polly/lib/External/isl/interface/extract_interface.cc
@@ -587,7 +587,6 @@
 
 	delete sema;
 	delete Clang;
-	llvm::llvm_shutdown();
 
 	if (Diags.hasErrorOccurred())
 		return EXIT_FAILURE;
Index: mlir/tools/mlir-vulkan-runner/mlir-vulkan-runner.cpp
===================================================================
--- mlir/tools/mlir-vulkan-runner/mlir-vulkan-runner.cpp
+++ mlir/tools/mlir-vulkan-runner/mlir-vulkan-runner.cpp
@@ -61,7 +61,6 @@
 }
 
 int main(int argc, char **argv) {
-  llvm::llvm_shutdown_obj x;
   registerPassManagerCLOptions();
 
   llvm::InitLLVM y(argc, argv);
Index: llvm/utils/KillTheDoctor/KillTheDoctor.cpp
===================================================================
--- llvm/utils/KillTheDoctor/KillTheDoctor.cpp
+++ llvm/utils/KillTheDoctor/KillTheDoctor.cpp
@@ -297,7 +297,6 @@
   // Print a stack trace if we signal out.
   sys::PrintStackTraceOnErrorSignal(argv[0]);
   PrettyStackTraceProgram X(argc, argv);
-  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
 
   ToolName = argv[0];
 
Index: llvm/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp
===================================================================
--- llvm/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp
+++ llvm/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp
@@ -59,7 +59,6 @@
 TEST(DynamicLibrary, Overload) {
   {
     std::string Err;
-    llvm_shutdown_obj Shutdown;
     DynamicLibrary DL =
         DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err);
     EXPECT_TRUE(DL.isValid());
@@ -109,9 +108,6 @@
   }
   EXPECT_TRUE(FuncPtr<GetString>(DynamicLibrary::SearchForAddressOfSymbol(
                   "TestA")) == nullptr);
-
-  // Check serach ordering is reset to default after call to llvm_shutdown
-  EXPECT_EQ(DynamicLibrary::SearchOrder, DynamicLibrary::SO_Linker);
 }
 
 TEST(DynamicLibrary, Shutdown) {
@@ -119,7 +115,6 @@
   std::vector<std::string> Order;
   {
     std::string Err;
-    llvm_shutdown_obj Shutdown;
     DynamicLibrary DL =
         DynamicLibrary::getPermanentLibrary(LibPath(A).c_str(), &Err);
     EXPECT_TRUE(DL.isValid());
Index: llvm/unittests/ExecutionEngine/ExecutionEngineTest.cpp
===================================================================
--- llvm/unittests/ExecutionEngine/ExecutionEngineTest.cpp
+++ llvm/unittests/ExecutionEngine/ExecutionEngineTest.cpp
@@ -22,9 +22,6 @@
 namespace {
 
 class ExecutionEngineTest : public testing::Test {
-private:
-  llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
-
 protected:
   ExecutionEngineTest() {
     auto Owner = std::make_unique<Module>("<main>", Context);
Index: llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
===================================================================
--- llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
+++ llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
@@ -435,7 +435,6 @@
   // Print a stack trace if we signal out.
   sys::PrintStackTraceOnErrorSignal(argv[0]);
   PrettyStackTraceProgram X(argc, argv);
-  llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
 
   llvm::InitializeAllTargets();
 
Index: llvm/tools/gold/gold-plugin.cpp
===================================================================
--- llvm/tools/gold/gold-plugin.cpp
+++ llvm/tools/gold/gold-plugin.cpp
@@ -1131,7 +1131,6 @@
     return LDPS_OK;
 
   if (options::thinlto_index_only) {
-    llvm_shutdown();
     cleanup_hook();
     exit(0);
   }
@@ -1149,7 +1148,6 @@
 
 static ld_plugin_status all_symbols_read_hook(void) {
   ld_plugin_status Ret = allSymbolsReadHook();
-  llvm_shutdown();
 
   if (options::TheOutputType == options::OT_BC_ONLY ||
       options::TheOutputType == options::OT_ASM_ONLY ||
Index: llvm/lib/Support/Windows/DynamicLibrary.inc
===================================================================
--- llvm/lib/Support/Windows/DynamicLibrary.inc
+++ llvm/lib/Support/Windows/DynamicLibrary.inc
@@ -28,7 +28,7 @@
 
   // 'Process' should not be released on Windows.
   assert((!Process || Process==this) && "Bad Handle");
-  // llvm_shutdown called, Return to default
+  // Global destructors run, Return to default
   DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker;
 }
 
Index: llvm/lib/Support/Unix/Signals.inc
===================================================================
--- llvm/lib/Support/Unix/Signals.inc
+++ llvm/lib/Support/Unix/Signals.inc
@@ -17,8 +17,8 @@
 // a signal handler for 2 reasons:
 //
 //  1. Creating a new one allocates.
-//  2. The signal handler could fire while llvm_shutdown is being processed, in
-//     which case the ManagedStatic is in an unknown state because it could
+//  2. The signal handler could fire while ManagedStatics are being destroyed,
+//     in which case the ManagedStatic is in an unknown state because it could
 //     already have been destroyed, or be in the process of being destroyed.
 //
 // Modifying the behavior of the signal handlers (such as registering new ones)
@@ -191,8 +191,9 @@
 static std::atomic<FileToRemoveList *> FilesToRemove = ATOMIC_VAR_INIT(nullptr);
 
 /// Clean up the list in a signal-friendly manner.
-/// Recall that signals can fire during llvm_shutdown. If this occurs we should
-/// either clean something up or nothing at all, but we shouldn't crash!
+/// Recall that signals can fire while ManagedStatic destructors are run. If
+/// this occurs we should either clean something up or nothing at all, but we
+/// shouldn't crash!
 struct FilesToRemoveCleanup {
   // Not signal-safe.
   ~FilesToRemoveCleanup() {
Index: llvm/lib/Support/Unix/DynamicLibrary.inc
===================================================================
--- llvm/lib/Support/Unix/DynamicLibrary.inc
+++ llvm/lib/Support/Unix/DynamicLibrary.inc
@@ -20,7 +20,7 @@
   if (Process)
     ::dlclose(Process);
 
-  // llvm_shutdown called, Return to default
+  // Global destructors run, Return to default
   DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker;
 }
 
Index: llvm/lib/Support/Statistic.cpp
===================================================================
--- llvm/lib/Support/Statistic.cpp
+++ llvm/lib/Support/Statistic.cpp
@@ -28,6 +28,7 @@
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/FastShutdown.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/Mutex.h"
@@ -59,8 +60,8 @@
 
 namespace {
 /// This class is used in a ManagedStatic so that it is created on demand (when
-/// the first statistic is bumped) and destroyed only when llvm_shutdown is
-/// called. We print statistics from the destructor.
+/// the first statistic is bumped) and destroyed only when ManagedStatics are
+/// destroyed. We print statistics from the destructor.
 /// This class is also used to look up statistic values from applications that
 /// use LLVM.
 class StatisticInfo {
@@ -98,7 +99,7 @@
 void TrackingStatistic::RegisterStatistic() {
   // If stats are enabled, inform StatInfo that this statistic should be
   // printed.
-  // llvm_shutdown calls destructors while holding the ManagedStatic mutex.
+  // ManagedStatic destructors are called while holding the ManagedStatic mutex.
   // These destructors end up calling PrintStatistics, which takes StatLock.
   // Since dereferencing StatInfo and StatLock can require taking the
   // ManagedStatic mutex, doing so with StatLock held would lead to a lock
@@ -265,3 +266,10 @@
 void llvm::ResetStatistics() {
   StatInfo->reset();
 }
+
+void llvm::fast_shutdown_statistics() {
+  if (StatInfo.peek()) {
+    if (EnableStats || PrintOnExit)
+      PrintStatistics();
+  }
+}
Index: llvm/lib/Support/Parallel.cpp
===================================================================
--- llvm/lib/Support/Parallel.cpp
+++ llvm/lib/Support/Parallel.cpp
@@ -8,6 +8,7 @@
 
 #include "llvm/Support/Parallel.h"
 #include "llvm/Config/llvm-config.h"
+#include "llvm/Support/FastShutdown.h"
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/Threading.h"
 
@@ -79,13 +80,6 @@
         T.join();
   }
 
-  struct Creator {
-    static void *call() { return new ThreadPoolExecutor(strategy); }
-  };
-  struct Deleter {
-    static void call(void *Ptr) { ((ThreadPoolExecutor *)Ptr)->stop(); }
-  };
-
   void add(std::function<void()> F) override {
     {
       std::lock_guard<std::mutex> Lock(Mutex);
@@ -117,31 +111,10 @@
   std::vector<std::thread> Threads;
 };
 
-Executor *Executor::getDefaultExecutor() {
-  // The ManagedStatic enables the ThreadPoolExecutor to be stopped via
-  // llvm_shutdown() which allows a "clean" fast exit, e.g. via _exit(). This
-  // stops the thread pool and waits for any worker thread creation to complete
-  // but does not wait for the threads to finish. The wait for worker thread
-  // creation to complete is important as it prevents intermittent crashes on
-  // Windows due to a race condition between thread creation and process exit.
-  //
-  // The ThreadPoolExecutor will only be destroyed when the static unique_ptr to
-  // it is destroyed, i.e. in a normal full exit. The ThreadPoolExecutor
-  // destructor ensures it has been stopped and waits for worker threads to
-  // finish. The wait is important as it prevents intermittent crashes on
-  // Windows when the process is doing a full exit.
-  //
-  // The Windows crashes appear to only occur with the MSVC static runtimes and
-  // are more frequent with the debug static runtime.
-  //
-  // This also prevents intermittent deadlocks on exit with the MinGW runtime.
+static ManagedStatic<ThreadPoolExecutor> DefaultExecutor;
+
+Executor *Executor::getDefaultExecutor() { return &*DefaultExecutor; }
 
-  static ManagedStatic<ThreadPoolExecutor, ThreadPoolExecutor::Creator,
-                       ThreadPoolExecutor::Deleter>
-      ManagedExec;
-  static std::unique_ptr<ThreadPoolExecutor> Exec(&(*ManagedExec));
-  return Exec.get();
-}
 } // namespace
 
 static std::atomic<int> TaskGroupInstances;
@@ -175,6 +148,32 @@
 } // namespace llvm
 #endif // LLVM_ENABLE_THREADS
 
+void llvm::fast_shutdown_parallel() {
+#if LLVM_ENABLE_THREADS
+  // Stop the executor, but only if it has been started.
+  //
+  // This allows a "clean" fast exit, via llvm_fast_shutdown() and e.g. _exit().
+  // This stops the thread pool and waits for any worker thread creation to
+  // complete but does not wait for the threads to finish. The wait for worker
+  // thread creation to complete is important as it prevents intermittent
+  // crashes on Windows due to a race condition between thread creation and
+  // process exit.
+  //
+  // The ThreadPoolExecutor will only be destroyed when the static unique_ptr to
+  // it is destroyed, i.e. in a normal full exit. The ThreadPoolExecutor
+  // destructor ensures it has been stopped and waits for worker threads to
+  // finish. The wait is important as it prevents intermittent crashes on
+  // Windows when the process is doing a full exit.
+  //
+  // The Windows crashes appear to only occur with the MSVC static runtimes and
+  // are more frequent with the debug static runtime.
+  //
+  // This also prevents intermittent deadlocks on exit with the MinGW runtime.
+  if (auto *Executor = parallel::detail::DefaultExecutor.peek())
+    Executor->stop();
+#endif
+}
+
 void llvm::parallelForEachN(size_t Begin, size_t End,
                             llvm::function_ref<void(size_t)> Fn) {
   // If we have zero or one items, then do not incur the overhead of spinning up
Index: llvm/lib/Support/ManagedStatic.cpp
===================================================================
--- llvm/lib/Support/ManagedStatic.cpp
+++ llvm/lib/Support/ManagedStatic.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file implements the ManagedStatic class and llvm_shutdown().
+// This file implements the ManagedStatic class.
 //
 //===----------------------------------------------------------------------===//
 
@@ -17,15 +17,12 @@
 #include <mutex>
 using namespace llvm;
 
-static const ManagedStaticBase *StaticList = nullptr;
-
 static std::recursive_mutex *getManagedStaticMutex() {
   static std::recursive_mutex m;
   return &m;
 }
 
-void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(),
-                                              void (*Deleter)(void*)) const {
+void ManagedStaticBase::create(void *(*Creator)()) const {
   assert(Creator);
   if (llvm_is_multithreaded()) {
     std::lock_guard<std::recursive_mutex> Lock(*getManagedStaticMutex());
@@ -34,45 +31,9 @@
       void *Tmp = Creator();
 
       Ptr.store(Tmp, std::memory_order_release);
-      DeleterFn = Deleter;
-
-      // Add to list of managed statics.
-      Next = StaticList;
-      StaticList = this;
     }
   } else {
-    assert(!Ptr && !DeleterFn && !Next &&
-           "Partially initialized ManagedStatic!?");
+    assert(!Ptr && "Partially initialized ManagedStatic!?");
     Ptr = Creator();
-    DeleterFn = Deleter;
-
-    // Add to list of managed statics.
-    Next = StaticList;
-    StaticList = this;
   }
 }
-
-void ManagedStaticBase::destroy() const {
-  assert(DeleterFn && "ManagedStatic not initialized correctly!");
-  assert(StaticList == this &&
-         "Not destroyed in reverse order of construction?");
-  // Unlink from list.
-  StaticList = Next;
-  Next = nullptr;
-
-  // Destroy memory.
-  DeleterFn(Ptr);
-
-  // Cleanup.
-  Ptr = nullptr;
-  DeleterFn = nullptr;
-}
-
-/// llvm_shutdown - Deallocate and destroy all ManagedStatic variables.
-/// IMPORTANT: it's only safe to call llvm_shutdown() in single thread,
-/// without any other threads executing LLVM APIs.
-/// llvm_shutdown() should be the last use of LLVM APIs.
-void llvm::llvm_shutdown() {
-  while (StaticList)
-    StaticList->destroy();
-}
Index: llvm/lib/Support/InitLLVM.cpp
===================================================================
--- llvm/lib/Support/InitLLVM.cpp
+++ llvm/lib/Support/InitLLVM.cpp
@@ -60,5 +60,3 @@
   Argv = Args.data();
 #endif
 }
-
-InitLLVM::~InitLLVM() { llvm_shutdown(); }
Index: llvm/lib/Support/FastShutdown.cpp
===================================================================
--- /dev/null
+++ llvm/lib/Support/FastShutdown.cpp
@@ -0,0 +1,16 @@
+//===-- FastShutdown.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/FastShutdown.h"
+
+using namespace llvm;
+
+void llvm::llvm_fast_shutdown() {
+  fast_shutdown_statistics();
+  fast_shutdown_parallel();
+}
Index: llvm/lib/Support/CMakeLists.txt
===================================================================
--- llvm/lib/Support/CMakeLists.txt
+++ llvm/lib/Support/CMakeLists.txt
@@ -152,6 +152,7 @@
   Error.cpp
   ErrorHandling.cpp
   ExtensibleRTTI.cpp
+  FastShutdown.cpp
   FileCollector.cpp
   FileUtilities.cpp
   FileOutputBuffer.cpp
Index: llvm/lib/IR/PassRegistry.cpp
===================================================================
--- llvm/lib/IR/PassRegistry.cpp
+++ llvm/lib/IR/PassRegistry.cpp
@@ -22,11 +22,6 @@
 
 using namespace llvm;
 
-// FIXME: We use ManagedStatic to erase the pass registrar on shutdown.
-// Unfortunately, passes are registered with static ctors, and having
-// llvm_shutdown clear this map prevents successful resurrection after
-// llvm_shutdown is run.  Ideally we should find a solution so that we don't
-// leak the map, AND can still resurrect after shutdown.
 static ManagedStatic<PassRegistry> PassRegistryObj;
 PassRegistry *PassRegistry::getPassRegistry() {
   return &*PassRegistryObj;
Index: llvm/lib/IR/Pass.cpp
===================================================================
--- llvm/lib/IR/Pass.cpp
+++ llvm/lib/IR/Pass.cpp
@@ -227,8 +227,8 @@
 }
 
 // This only gets called during static destruction, in which case the
-// PassRegistry will have already been destroyed by llvm_shutdown().  So
-// attempting to remove the registration listener is an error.
+// PassRegistry may have already been destroyed. So attempting to remove the
+// registration listener is an error (and also unnecessary).
 PassNameParser::~PassNameParser() = default;
 
 //===----------------------------------------------------------------------===//
Index: llvm/lib/IR/Core.cpp
===================================================================
--- llvm/lib/IR/Core.cpp
+++ llvm/lib/IR/Core.cpp
@@ -57,9 +57,8 @@
   initializeCore(*unwrap(R));
 }
 
-void LLVMShutdown() {
-  llvm_shutdown();
-}
+// Deprecated.
+void LLVMShutdown() {}
 
 /*===-- Error handling ----------------------------------------------------===*/
 
Index: llvm/include/llvm/Support/ManagedStatic.h
===================================================================
--- llvm/include/llvm/Support/ManagedStatic.h
+++ llvm/include/llvm/Support/ManagedStatic.h
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file defines the ManagedStatic class and the llvm_shutdown() function.
+// This file defines the ManagedStatic class.
 //
 //===----------------------------------------------------------------------===//
 
@@ -50,17 +50,13 @@
 protected:
 #ifdef LLVM_USE_CONSTEXPR_CTOR
   mutable std::atomic<void *> Ptr{};
-  mutable void (*DeleterFn)(void *) = nullptr;
-  mutable const ManagedStaticBase *Next = nullptr;
 #else
   // This should only be used as a static variable, which guarantees that this
   // will be zero initialized.
   mutable std::atomic<void *> Ptr;
-  mutable void (*DeleterFn)(void *);
-  mutable const ManagedStaticBase *Next;
 #endif
 
-  void RegisterManagedStatic(void *(*creator)(), void (*deleter)(void*)) const;
+  void create(void *(*creator)()) const;
 
 public:
 #ifdef LLVM_USE_CONSTEXPR_CTOR
@@ -69,40 +65,62 @@
 
   /// isConstructed - Return true if this object has not been created yet.
   bool isConstructed() const { return Ptr != nullptr; }
-
-  void destroy() const;
 };
 
 /// ManagedStatic - This transparently changes the behavior of global statics to
 /// be lazily constructed on demand (good for reducing startup times of dynamic
-/// libraries that link in LLVM components) and for making destruction be
-/// explicit through the llvm_shutdown() function call.
+/// libraries that link in LLVM components).
 ///
 template <class C, class Creator = object_creator<C>,
           class Deleter = object_deleter<C>>
 class ManagedStatic : public ManagedStaticBase {
 public:
+  ~ManagedStatic() { destroy(); }
+
+  /// Destroy the managed static if it has been constructed.
+  ///
+  /// IMPORTANT: This must only be called from a single thread when it is known
+  ///            that no other thread accesses managed statics.
+  void destroy() {
+    if (isConstructed()) {
+      Deleter::call(Ptr.load(std::memory_order_relaxed));
+      Ptr = nullptr;
+    }
+  }
+
   // Accessors.
   C &operator*() {
     void *Tmp = Ptr.load(std::memory_order_acquire);
     if (!Tmp)
-      RegisterManagedStatic(Creator::call, Deleter::call);
+      create(Creator::call);
 
     return *static_cast<C *>(Ptr.load(std::memory_order_relaxed));
   }
 
   C *operator->() { return &**this; }
 
+  // Retrieve the managed static or nullptr if it has not been initialized. This
+  // is useful in code run from global destructors where the order of
+  // destructors cannot be guaranteed.
+  C *peek() { return static_cast<C *>(Ptr.load(std::memory_order_relaxed)); }
+
   const C &operator*() const {
     void *Tmp = Ptr.load(std::memory_order_acquire);
     if (!Tmp)
-      RegisterManagedStatic(Creator::call, Deleter::call);
+      create(Creator::call);
 
     return *static_cast<C *>(Ptr.load(std::memory_order_relaxed));
   }
 
   const C *operator->() const { return &**this; }
 
+  // Retrieve the managed static or nullptr if it has not been initialized. This
+  // is useful in code run from global destructors where the order of
+  // destructors cannot be guaranteed.
+  const C *peek() const {
+    return static_cast<C *>(Ptr.load(std::memory_order_relaxed));
+  }
+
   // Extract the instance, leaving the ManagedStatic uninitialized. The
   // user is then responsible for the lifetime of the returned instance.
   C *claim() {
@@ -110,15 +128,12 @@
   }
 };
 
-/// llvm_shutdown - Deallocate and destroy all ManagedStatic variables.
-void llvm_shutdown();
+[[deprecated("llvm_shutdown is a no-op; shutdown now happens by "
+             "default")]] static inline void
+llvm_shutdown() {}
 
-/// llvm_shutdown_obj - This is a simple helper class that calls
-/// llvm_shutdown() when it is destroyed.
-struct llvm_shutdown_obj {
-  llvm_shutdown_obj() = default;
-  ~llvm_shutdown_obj() { llvm_shutdown(); }
-};
+struct [[deprecated("llvm_shutdown_obj is a no-op; shutdown now happens by "
+                    "default")]] llvm_shutdown_obj{};
 
 } // end namespace llvm
 
Index: llvm/include/llvm/Support/InitLLVM.h
===================================================================
--- llvm/include/llvm/Support/InitLLVM.h
+++ llvm/include/llvm/Support/InitLLVM.h
@@ -29,8 +29,6 @@
 //     encoding, so that you can assume that command line arguments are
 //     always encoded in UTF-8 on any platform.
 //
-// InitLLVM calls llvm_shutdown() on destruction, which cleans up
-// ManagedStatic objects.
 namespace llvm {
 class InitLLVM {
 public:
@@ -40,8 +38,6 @@
       : InitLLVM(Argc, const_cast<const char **&>(Argv),
                  InstallPipeSignalExitHandler) {}
 
-  ~InitLLVM();
-
 private:
   BumpPtrAllocator Alloc;
   SmallVector<const char *, 0> Args;
Index: llvm/include/llvm/Support/FastShutdown.h
===================================================================
--- /dev/null
+++ llvm/include/llvm/Support/FastShutdown.h
@@ -0,0 +1,38 @@
+//===-- llvm/Support/FastShutdown.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helpers to allow a fast process shutdown without the normal cleanups
+// (e.g., using _exit) but with some desirable side-effects that usually happen
+// when global static destructors are run.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FASTSHUTDOWN_H
+#define LLVM_SUPPORT_FASTSHUTDOWN_H
+
+namespace llvm {
+
+/// Run a small set of operations that usually run from global static
+/// destructors, but which have side-effects (e.g., printing statistics) that
+/// are desirable for tools that want to do a fast process exit without cleanups
+/// (e.g., using _exit).
+///
+/// Note that if the process exits (or LLVM is unloaded) normally, calling this
+/// function isn't necessary and should be avoided.
+///
+/// IMPORTANT: It's only safe to call llvm_fast_shutdown() in a single thread,
+/// without any other threads executing LLVM APIs. No LLVM APIs should be used
+/// after calling this function (other than sys::Process::Exit).
+void llvm_fast_shutdown();
+
+void fast_shutdown_statistics();
+void fast_shutdown_parallel();
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_FASTSHUTDOWN_H
Index: llvm/include/llvm/Support/DynamicLibrary.h
===================================================================
--- llvm/include/llvm/Support/DynamicLibrary.h
+++ llvm/include/llvm/Support/DynamicLibrary.h
@@ -57,7 +57,8 @@
     void *getAddressOfSymbol(const char *symbolName);
 
     /// This function permanently loads the dynamic library at the given path.
-    /// The library will only be unloaded when llvm_shutdown() is called.
+    /// The library will only be unloaded when LLVM's global destructors are
+    /// run.
     /// This returns a valid DynamicLibrary instance on success and an invalid
     /// instance on failure (see isValid()). \p *errMsg will only be modified
     /// if the library fails to load.
Index: llvm/include/llvm/PassRegistry.h
===================================================================
--- llvm/include/llvm/PassRegistry.h
+++ llvm/include/llvm/PassRegistry.h
@@ -53,8 +53,8 @@
   ~PassRegistry();
 
   /// getPassRegistry - Access the global registry object, which is
-  /// automatically initialized at application launch and destroyed by
-  /// llvm_shutdown.
+  /// automatically initialized at application launch and destroyed when
+  /// global destructors are run.
   static PassRegistry *getPassRegistry();
 
   /// getPassInfo - Look up a pass' corresponding PassInfo, indexed by the pass'
Index: llvm/include/llvm/ADT/Statistic.h
===================================================================
--- llvm/include/llvm/ADT/Statistic.h
+++ llvm/include/llvm/ADT/Statistic.h
@@ -9,8 +9,8 @@
 /// \file
 /// This file defines the 'Statistic' class, which is designed to be an easy way
 /// to expose various metrics from passes.  These statistics are printed at the
-/// end of a run (from llvm_shutdown), when the -stats command line option is
-/// passed on the command line.
+/// end of a run (during cleanup of ManagedStatics), when the -stats command
+/// line option is passed on the command line.
 ///
 /// This is useful for reporting information like the number of instructions
 /// simplified, optimized or removed by various transformations, like this:
Index: llvm/include/llvm-c/Core.h
===================================================================
--- llvm/include/llvm-c/Core.h
+++ llvm/include/llvm-c/Core.h
@@ -468,10 +468,10 @@
 
 void LLVMInitializeCore(LLVMPassRegistryRef R);
 
-/** Deallocate and destroy all ManagedStatic variables.
-    @see llvm::llvm_shutdown
-    @see ManagedStatic */
-void LLVMShutdown(void);
+LLVM_ATTRIBUTE_C_DEPRECATED(
+    void LLVMShutdown(void),
+    "This is a no-op; destruction of ManagedStatic variables now happens by "
+    "default");
 
 /*===-- Error handling ----------------------------------------------------===*/
 
Index: llvm/examples/HowToUseJIT/HowToUseJIT.cpp
===================================================================
--- llvm/examples/HowToUseJIT/HowToUseJIT.cpp
+++ llvm/examples/HowToUseJIT/HowToUseJIT.cpp
@@ -135,6 +135,5 @@
   // Import result of execution:
   outs() << "Result: " << gv.IntVal << "\n";
   delete EE;
-  llvm_shutdown();
   return 0;
 }
Index: llvm/examples/BrainF/BrainFDriver.cpp
===================================================================
--- llvm/examples/BrainF/BrainFDriver.cpp
+++ llvm/examples/BrainF/BrainFDriver.cpp
@@ -180,7 +180,5 @@
   if (out != &outs())
     delete out;
 
-  llvm_shutdown();
-
   return 0;
 }
Index: llvm/docs/ProgrammersManual.rst
===================================================================
--- llvm/docs/ProgrammersManual.rst
+++ llvm/docs/ProgrammersManual.rst
@@ -3043,14 +3043,6 @@
 using the resultant compiler to build a copy of LLVM with multithreading
 support.
 
-.. _shutdown:
-
-Ending Execution with ``llvm_shutdown()``
------------------------------------------
-
-When you are done using the LLVM APIs, you should call ``llvm_shutdown()`` to
-deallocate memory used for internal structures.
-
 .. _managedstatic:
 
 Lazy Initialization with ``ManagedStatic``
Index: lldb/utils/TableGen/LLDBTableGen.cpp
===================================================================
--- lldb/utils/TableGen/LLDBTableGen.cpp
+++ lldb/utils/TableGen/LLDBTableGen.cpp
@@ -68,8 +68,6 @@
   PrettyStackTraceProgram X(argc, argv);
   cl::ParseCommandLineOptions(argc, argv);
 
-  llvm_shutdown_obj Y;
-
   return TableGenMain(argv[0], &LLDBTableGenMain);
 }
 
Index: lldb/unittests/Utility/LogTest.cpp
===================================================================
--- lldb/unittests/Utility/LogTest.cpp
+++ lldb/unittests/Utility/LogTest.cpp
@@ -74,7 +74,6 @@
 
   static void TearDownTestCase() {
     Log::Unregister("chan");
-    llvm::llvm_shutdown();
   }
 };
 
@@ -126,7 +125,6 @@
 }
 
 TEST(LogTest, Register) {
-  llvm::llvm_shutdown_obj obj;
   Log::Register("chan", test_channel);
   Log::Unregister("chan");
   Log::Register("chan", test_channel);
@@ -134,7 +132,6 @@
 }
 
 TEST(LogTest, Unregister) {
-  llvm::llvm_shutdown_obj obj;
   Log::Register("chan", test_channel);
   EXPECT_EQ(nullptr, GetLog(TestChannel::FOO));
   std::string message;
Index: lldb/tools/lldb-test/lldb-test.cpp
===================================================================
--- lldb/tools/lldb-test/lldb-test.cpp
+++ lldb/tools/lldb-test/lldb-test.cpp
@@ -1091,7 +1091,6 @@
   StringRef ToolName = argv[0];
   sys::PrintStackTraceOnErrorSignal(ToolName);
   PrettyStackTraceProgram X(argc, argv);
-  llvm_shutdown_obj Y;
 
   cl::ParseCommandLineOptions(argc, argv, "LLDB Testing Utility\n");
 
Index: lldb/tools/driver/Driver.cpp
===================================================================
--- lldb/tools/driver/Driver.cpp
+++ lldb/tools/driver/Driver.cpp
@@ -780,8 +780,7 @@
   std::setlocale(LC_ALL, "");
   std::setlocale(LC_CTYPE, "");
 
-  // Setup LLVM signal handlers and make sure we call llvm_shutdown() on
-  // destruction.
+  // Setup LLVM signal handlers.
   llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
 
   // Parse arguments.
Index: lld/Common/ErrorHandler.cpp
===================================================================
--- lld/Common/ErrorHandler.cpp
+++ lld/Common/ErrorHandler.cpp
@@ -15,7 +15,7 @@
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/DiagnosticPrinter.h"
 #include "llvm/Support/CrashRecoveryContext.h"
-#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/FastShutdown.h"
 #include "llvm/Support/Process.h"
 #include "llvm/Support/Program.h"
 #include "llvm/Support/raw_ostream.h"
@@ -99,12 +99,11 @@
   // safeLldMain().
   CrashRecoveryContext::throwIfCrash(val);
 
-  // Dealloc/destroy ManagedStatic variables before calling _exit().
-  // In an LTO build, allows us to get the output of -time-passes.
-  // Ensures that the thread pool for the parallel algorithms is stopped to
-  // avoid intermittent crashes on Windows when exiting.
+  // We will call _exit() but want to get the output of -time-passes in an LTO
+  // build. Also ensures that the thread pool for the parallel algorithms is
+  // stopped to avoid intermittent crashes on Windows when exiting.
   if (!CrashRecoveryContext::GetCurrent())
-    llvm_shutdown();
+    llvm_fast_shutdown();
 
   if (hasContext())
     lld::errorHandler().flushStreams();
Index: libclc/utils/prepare-builtins.cpp
===================================================================
--- libclc/utils/prepare-builtins.cpp
+++ libclc/utils/prepare-builtins.cpp
@@ -31,7 +31,6 @@
 
 int main(int argc, char **argv) {
   LLVMContext Context;
-  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
 
   cl::ParseCommandLineOptions(argc, argv, "libclc builtin preparation tool\n");
 
Index: clang/utils/TableGen/TableGen.cpp
===================================================================
--- clang/utils/TableGen/TableGen.cpp
+++ clang/utils/TableGen/TableGen.cpp
@@ -484,8 +484,6 @@
   PrettyStackTraceProgram X(argc, argv);
   cl::ParseCommandLineOptions(argc, argv);
 
-  llvm_shutdown_obj Y;
-
   return TableGenMain(argv[0], &ClangTableGenMain);
 }
 
Index: clang/unittests/Interpreter/InterpreterTest.cpp
===================================================================
--- clang/unittests/Interpreter/InterpreterTest.cpp
+++ clang/unittests/Interpreter/InterpreterTest.cpp
@@ -142,7 +142,6 @@
     llvm::InitializeNativeTarget();
     llvm::InitializeNativeTargetAsmPrinter();
   }
-  ~LLVMInitRAII() { llvm::llvm_shutdown(); }
 } LLVMInit;
 
 #ifdef _AIX
Index: clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp
===================================================================
--- clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp
+++ clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp
@@ -131,8 +131,6 @@
   EXPECT_ANY_THROW(ThrowException());
   std::string CapturedStdOut = testing::internal::GetCapturedStdout();
   EXPECT_EQ(CapturedStdOut, "Caught: 'To be caught in JIT'\n");
-
-  llvm::llvm_shutdown();
 }
 
 } // end anonymous namespace
Index: clang/tools/clang-repl/ClangRepl.cpp
===================================================================
--- clang/tools/clang-repl/ClangRepl.cpp
+++ clang/tools/clang-repl/ClangRepl.cpp
@@ -18,7 +18,6 @@
 #include "llvm/ExecutionEngine/Orc/LLJIT.h"
 #include "llvm/LineEditor/LineEditor.h"
 #include "llvm/Support/CommandLine.h"
-#include "llvm/Support/ManagedStatic.h" // llvm_shutdown
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/TargetSelect.h" // llvm::Initialize*
 
@@ -104,7 +103,5 @@
   // later errors use the default handling behavior instead.
   llvm::remove_fatal_error_handler();
 
-  llvm::llvm_shutdown();
-
   return 0;
 }
Index: clang/include/clang/Frontend/CompilerInstance.h
===================================================================
--- clang/include/clang/Frontend/CompilerInstance.h
+++ clang/include/clang/Frontend/CompilerInstance.h
@@ -205,16 +205,10 @@
   ///  - Clients should have initialized any LLVM target features that may be
   ///    required.
   ///
-  ///  - Clients should eventually call llvm_shutdown() upon the completion of
-  ///    this routine to ensure that any managed objects are properly destroyed.
-  ///
   /// Note that this routine may write output to 'stderr'.
   ///
   /// \param Act - The action to execute.
   /// \return - True on success.
-  //
-  // FIXME: Eliminate the llvm_shutdown requirement, that should either be part
-  // of the context or else not CompilerInstance specific.
   bool ExecuteAction(FrontendAction &Act);
 
   /// Load the list of plugins requested in the \c FrontendOptions.
Index: bolt/tools/merge-fdata/merge-fdata.cpp
===================================================================
--- bolt/tools/merge-fdata/merge-fdata.cpp
+++ bolt/tools/merge-fdata/merge-fdata.cpp
@@ -315,8 +315,6 @@
   sys::PrintStackTraceOnErrorSignal(argv[0]);
   PrettyStackTraceProgram X(argc, argv);
 
-  llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
-
   cl::HideUnrelatedOptions(opts::MergeFdataCategory);
 
   cl::ParseCommandLineOptions(argc, argv,
Index: bolt/tools/driver/llvm-bolt.cpp
===================================================================
--- bolt/tools/driver/llvm-bolt.cpp
+++ bolt/tools/driver/llvm-bolt.cpp
@@ -182,8 +182,6 @@
   sys::PrintStackTraceOnErrorSignal(argv[0]);
   PrettyStackTraceProgram X(argc, argv);
 
-  llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
-
   std::string ToolPath = GetExecutablePath(argv[0]);
 
   // Initialize targets and assembly printers/parsers.
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
  • [Lldb-commits] [PATCH] D1... Nicolai Hähnle via Phabricator via lldb-commits

Reply via email to