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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits