xref: /llvm-project/clang-tools-extra/clangd/support/ThreadCrashReporter.cpp (revision e4e0f933079859c12983f955e7ee66ba4fb39932)
1045695f8SEmma Blink //===--- ThreadCrashReporter.cpp - Thread local signal handling --*- C++-*-===//
2045695f8SEmma Blink //
3045695f8SEmma Blink // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4045695f8SEmma Blink // See https://llvm.org/LICENSE.txt for license information.
5045695f8SEmma Blink // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6045695f8SEmma Blink //
7045695f8SEmma Blink //===----------------------------------------------------------------------===//
8045695f8SEmma Blink 
9045695f8SEmma Blink #include "support/ThreadCrashReporter.h"
10ba94b8bdSShoaib Meenai #include <atomic>
11045695f8SEmma Blink 
12045695f8SEmma Blink namespace clang {
13045695f8SEmma Blink namespace clangd {
14045695f8SEmma Blink 
15045695f8SEmma Blink static thread_local ThreadCrashReporter *CurrentReporter = nullptr;
16045695f8SEmma Blink 
runCrashHandlers()17045695f8SEmma Blink void ThreadCrashReporter::runCrashHandlers() {
18045695f8SEmma Blink   // No signal handling is done here on top of what AddSignalHandler() does:
19045695f8SEmma Blink   // on Windows the signal handling is implmented via
20045695f8SEmma Blink   // SetUnhandledExceptionFilter() which is thread-directed, and on Unix
21045695f8SEmma Blink   // platforms the handlers are only called for KillSigs out of which only
22045695f8SEmma Blink   // SIGQUIT seems to be process-directed and would be delivered to any thread
23045695f8SEmma Blink   // that is not blocking it, but if the thread it gets delivered to has a
24045695f8SEmma Blink   // ThreadCrashReporter installed during the interrupt — it seems reasonable to
25045695f8SEmma Blink   // let it run and print the thread's context information.
26045695f8SEmma Blink 
27045695f8SEmma Blink   // Call the reporters in LIFO order.
28045695f8SEmma Blink   ThreadCrashReporter *Reporter = CurrentReporter;
29045695f8SEmma Blink   while (Reporter) {
30045695f8SEmma Blink     Reporter->Callback();
31045695f8SEmma Blink     Reporter = Reporter->Next;
32045695f8SEmma Blink   }
33045695f8SEmma Blink }
34045695f8SEmma Blink 
ThreadCrashReporter(SignalCallback ThreadLocalCallback)35045695f8SEmma Blink ThreadCrashReporter::ThreadCrashReporter(SignalCallback ThreadLocalCallback)
36045695f8SEmma Blink     : Callback(std::move(ThreadLocalCallback)), Next(nullptr) {
37045695f8SEmma Blink   this->Next = CurrentReporter;
38045695f8SEmma Blink   CurrentReporter = this;
39045695f8SEmma Blink   // Don't reorder subsequent operations: whatever comes after might crash and
40*c8f47925SRageking8   // we want the crash handler to see the reporter values we just set.
41045695f8SEmma Blink   std::atomic_signal_fence(std::memory_order_seq_cst);
42045695f8SEmma Blink }
43045695f8SEmma Blink 
~ThreadCrashReporter()44045695f8SEmma Blink ThreadCrashReporter::~ThreadCrashReporter() {
45045695f8SEmma Blink   assert(CurrentReporter == this);
46045695f8SEmma Blink   CurrentReporter = this->Next;
47045695f8SEmma Blink   // Don't reorder subsequent operations: whatever comes after might crash and
48*c8f47925SRageking8   // we want the crash handler to see the reporter values we just set.
49045695f8SEmma Blink   std::atomic_signal_fence(std::memory_order_seq_cst);
50045695f8SEmma Blink }
51045695f8SEmma Blink 
52045695f8SEmma Blink } // namespace clangd
53045695f8SEmma Blink } // namespace clang
54