diff --git a/bolt/tools/driver/llvm-bolt.cpp b/bolt/tools/driver/llvm-bolt.cpp --- a/bolt/tools/driver/llvm-bolt.cpp +++ b/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. diff --git a/bolt/tools/merge-fdata/merge-fdata.cpp b/bolt/tools/merge-fdata/merge-fdata.cpp --- a/bolt/tools/merge-fdata/merge-fdata.cpp +++ b/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, diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/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. diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp --- a/clang/tools/clang-repl/ClangRepl.cpp +++ b/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; } diff --git a/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp b/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp --- a/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp +++ b/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 diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp --- a/clang/unittests/Interpreter/InterpreterTest.cpp +++ b/clang/unittests/Interpreter/InterpreterTest.cpp @@ -142,7 +142,6 @@ llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); } - ~LLVMInitRAII() { llvm::llvm_shutdown(); } } LLVMInit; #ifdef _AIX diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp --- a/clang/utils/TableGen/TableGen.cpp +++ b/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); } diff --git a/libclc/utils/prepare-builtins.cpp b/libclc/utils/prepare-builtins.cpp --- a/libclc/utils/prepare-builtins.cpp +++ b/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"); diff --git a/lld/Common/ErrorHandler.cpp b/lld/Common/ErrorHandler.cpp --- a/lld/Common/ErrorHandler.cpp +++ b/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(); diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp --- a/lldb/tools/driver/Driver.cpp +++ b/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. diff --git a/lldb/tools/lldb-test/lldb-test.cpp b/lldb/tools/lldb-test/lldb-test.cpp --- a/lldb/tools/lldb-test/lldb-test.cpp +++ b/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"); diff --git a/lldb/unittests/Utility/LogTest.cpp b/lldb/unittests/Utility/LogTest.cpp --- a/lldb/unittests/Utility/LogTest.cpp +++ b/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; diff --git a/lldb/utils/TableGen/LLDBTableGen.cpp b/lldb/utils/TableGen/LLDBTableGen.cpp --- a/lldb/utils/TableGen/LLDBTableGen.cpp +++ b/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); } diff --git a/llvm/docs/ProgrammersManual.rst b/llvm/docs/ProgrammersManual.rst --- a/llvm/docs/ProgrammersManual.rst +++ b/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`` diff --git a/llvm/examples/BrainF/BrainFDriver.cpp b/llvm/examples/BrainF/BrainFDriver.cpp --- a/llvm/examples/BrainF/BrainFDriver.cpp +++ b/llvm/examples/BrainF/BrainFDriver.cpp @@ -180,7 +180,5 @@ if (out != &outs()) delete out; - llvm_shutdown(); - return 0; } diff --git a/llvm/examples/HowToUseJIT/HowToUseJIT.cpp b/llvm/examples/HowToUseJIT/HowToUseJIT.cpp --- a/llvm/examples/HowToUseJIT/HowToUseJIT.cpp +++ b/llvm/examples/HowToUseJIT/HowToUseJIT.cpp @@ -135,6 +135,5 @@ // Import result of execution: outs() << "Result: " << gv.IntVal << "\n"; delete EE; - llvm_shutdown(); return 0; } diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h --- a/llvm/include/llvm-c/Core.h +++ b/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 ----------------------------------------------------===*/ diff --git a/llvm/include/llvm/ADT/Statistic.h b/llvm/include/llvm/ADT/Statistic.h --- a/llvm/include/llvm/ADT/Statistic.h +++ b/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: diff --git a/llvm/include/llvm/PassRegistry.h b/llvm/include/llvm/PassRegistry.h --- a/llvm/include/llvm/PassRegistry.h +++ b/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' diff --git a/llvm/include/llvm/Support/DynamicLibrary.h b/llvm/include/llvm/Support/DynamicLibrary.h --- a/llvm/include/llvm/Support/DynamicLibrary.h +++ b/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. diff --git a/llvm/include/llvm/Support/FastShutdown.h b/llvm/include/llvm/Support/FastShutdown.h new file mode 100644 --- /dev/null +++ b/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 diff --git a/llvm/include/llvm/Support/InitLLVM.h b/llvm/include/llvm/Support/InitLLVM.h --- a/llvm/include/llvm/Support/InitLLVM.h +++ b/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(Argv), InstallPipeSignalExitHandler) {} - ~InitLLVM(); - private: BumpPtrAllocator Alloc; SmallVector Args; diff --git a/llvm/include/llvm/Support/ManagedStatic.h b/llvm/include/llvm/Support/ManagedStatic.h --- a/llvm/include/llvm/Support/ManagedStatic.h +++ b/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 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 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 Deleter = object_deleter> 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(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(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(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(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 diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp --- a/llvm/lib/IR/Core.cpp +++ b/llvm/lib/IR/Core.cpp @@ -57,9 +57,8 @@ initializeCore(*unwrap(R)); } -void LLVMShutdown() { - llvm_shutdown(); -} +// Deprecated. +void LLVMShutdown() {} /*===-- Error handling ----------------------------------------------------===*/ diff --git a/llvm/lib/IR/Pass.cpp b/llvm/lib/IR/Pass.cpp --- a/llvm/lib/IR/Pass.cpp +++ b/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; //===----------------------------------------------------------------------===// diff --git a/llvm/lib/IR/PassRegistry.cpp b/llvm/lib/IR/PassRegistry.cpp --- a/llvm/lib/IR/PassRegistry.cpp +++ b/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 PassRegistryObj; PassRegistry *PassRegistry::getPassRegistry() { return &*PassRegistryObj; diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -152,6 +152,7 @@ Error.cpp ErrorHandling.cpp ExtensibleRTTI.cpp + FastShutdown.cpp FileCollector.cpp FileUtilities.cpp FileOutputBuffer.cpp diff --git a/llvm/lib/Support/FastShutdown.cpp b/llvm/lib/Support/FastShutdown.cpp new file mode 100644 --- /dev/null +++ b/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(); +} diff --git a/llvm/lib/Support/InitLLVM.cpp b/llvm/lib/Support/InitLLVM.cpp --- a/llvm/lib/Support/InitLLVM.cpp +++ b/llvm/lib/Support/InitLLVM.cpp @@ -60,5 +60,3 @@ Argv = Args.data(); #endif } - -InitLLVM::~InitLLVM() { llvm_shutdown(); } diff --git a/llvm/lib/Support/ManagedStatic.cpp b/llvm/lib/Support/ManagedStatic.cpp --- a/llvm/lib/Support/ManagedStatic.cpp +++ b/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 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 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(); -} diff --git a/llvm/lib/Support/Parallel.cpp b/llvm/lib/Support/Parallel.cpp --- a/llvm/lib/Support/Parallel.cpp +++ b/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 F) override { { std::lock_guard Lock(Mutex); @@ -117,31 +111,10 @@ std::vector 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 DefaultExecutor; + +Executor *Executor::getDefaultExecutor() { return &*DefaultExecutor; } - static ManagedStatic - ManagedExec; - static std::unique_ptr Exec(&(*ManagedExec)); - return Exec.get(); -} } // namespace static std::atomic 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 Fn) { // If we have zero or one items, then do not incur the overhead of spinning up diff --git a/llvm/lib/Support/Statistic.cpp b/llvm/lib/Support/Statistic.cpp --- a/llvm/lib/Support/Statistic.cpp +++ b/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(); + } +} diff --git a/llvm/lib/Support/Unix/DynamicLibrary.inc b/llvm/lib/Support/Unix/DynamicLibrary.inc --- a/llvm/lib/Support/Unix/DynamicLibrary.inc +++ b/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; } diff --git a/llvm/lib/Support/Unix/Signals.inc b/llvm/lib/Support/Unix/Signals.inc --- a/llvm/lib/Support/Unix/Signals.inc +++ b/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 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() { diff --git a/llvm/lib/Support/Windows/DynamicLibrary.inc b/llvm/lib/Support/Windows/DynamicLibrary.inc --- a/llvm/lib/Support/Windows/DynamicLibrary.inc +++ b/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; } diff --git a/llvm/tools/gold/gold-plugin.cpp b/llvm/tools/gold/gold-plugin.cpp --- a/llvm/tools/gold/gold-plugin.cpp +++ b/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 || diff --git a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp --- a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp +++ b/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(); diff --git a/llvm/unittests/ExecutionEngine/ExecutionEngineTest.cpp b/llvm/unittests/ExecutionEngine/ExecutionEngineTest.cpp --- a/llvm/unittests/ExecutionEngine/ExecutionEngineTest.cpp +++ b/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("
", Context); diff --git a/llvm/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp b/llvm/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp --- a/llvm/unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp +++ b/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(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 Order; { std::string Err; - llvm_shutdown_obj Shutdown; DynamicLibrary DL = DynamicLibrary::getPermanentLibrary(LibPath(A).c_str(), &Err); EXPECT_TRUE(DL.isValid()); diff --git a/llvm/utils/KillTheDoctor/KillTheDoctor.cpp b/llvm/utils/KillTheDoctor/KillTheDoctor.cpp --- a/llvm/utils/KillTheDoctor/KillTheDoctor.cpp +++ b/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]; diff --git a/mlir/tools/mlir-vulkan-runner/mlir-vulkan-runner.cpp b/mlir/tools/mlir-vulkan-runner/mlir-vulkan-runner.cpp --- a/mlir/tools/mlir-vulkan-runner/mlir-vulkan-runner.cpp +++ b/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); diff --git a/polly/lib/External/isl/interface/extract_interface.cc b/polly/lib/External/isl/interface/extract_interface.cc --- a/polly/lib/External/isl/interface/extract_interface.cc +++ b/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;