1 //===--- ThreadCrashReporter.cpp - Thread local signal handling --*- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "support/ThreadCrashReporter.h"
10 #include "llvm/Support/ThreadLocal.h"
11 #include <atomic>
12 
13 namespace clang {
14 namespace clangd {
15 
16 static thread_local ThreadCrashReporter *CurrentReporter = nullptr;
17 
runCrashHandlers()18 void ThreadCrashReporter::runCrashHandlers() {
19   // No signal handling is done here on top of what AddSignalHandler() does:
20   // on Windows the signal handling is implmented via
21   // SetUnhandledExceptionFilter() which is thread-directed, and on Unix
22   // platforms the handlers are only called for KillSigs out of which only
23   // SIGQUIT seems to be process-directed and would be delivered to any thread
24   // that is not blocking it, but if the thread it gets delivered to has a
25   // ThreadCrashReporter installed during the interrupt — it seems reasonable to
26   // let it run and print the thread's context information.
27 
28   // Call the reporters in LIFO order.
29   ThreadCrashReporter *Reporter = CurrentReporter;
30   while (Reporter) {
31     Reporter->Callback();
32     Reporter = Reporter->Next;
33   }
34 }
35 
ThreadCrashReporter(SignalCallback ThreadLocalCallback)36 ThreadCrashReporter::ThreadCrashReporter(SignalCallback ThreadLocalCallback)
37     : Callback(std::move(ThreadLocalCallback)), Next(nullptr) {
38   this->Next = CurrentReporter;
39   CurrentReporter = this;
40   // Don't reorder subsequent operations: whatever comes after might crash and
41   // we want the the crash handler to see the reporter values we just set.
42   std::atomic_signal_fence(std::memory_order_seq_cst);
43 }
44 
~ThreadCrashReporter()45 ThreadCrashReporter::~ThreadCrashReporter() {
46   assert(CurrentReporter == this);
47   CurrentReporter = this->Next;
48   // Don't reorder subsequent operations: whatever comes after might crash and
49   // we want the the crash handler to see the reporter values we just set.
50   std::atomic_signal_fence(std::memory_order_seq_cst);
51 }
52 
53 } // namespace clangd
54 } // namespace clang
55