1 | ///===- ThreadCrashReporterTests.cpp - Thread local signal handling tests -===// |
---|---|
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 "support/Threading.h" |
11 | #include "llvm/Support/Signals.h" |
12 | #include "gtest/gtest.h" |
13 | #include <csignal> |
14 | #include <string> |
15 | |
16 | namespace clang { |
17 | namespace clangd { |
18 | |
19 | namespace { |
20 | |
21 | static void infoSignalHandler() { ThreadCrashReporter::runCrashHandlers(); } |
22 | |
23 | TEST(ThreadCrashReporterTest, All) { |
24 | #if defined(_WIN32) |
25 | // Simulate signals on Windows for unit testing purposes. |
26 | // The `crash.test` lit test checks the end-to-end integration. |
27 | auto SignalCurrentThread = []() { infoSignalHandler(); }; |
28 | #else |
29 | llvm::sys::SetInfoSignalFunction(&infoSignalHandler); |
30 | auto SignalCurrentThread = []() { raise(SIGUSR1); }; |
31 | #endif |
32 | |
33 | AsyncTaskRunner Runner; |
34 | auto SignalAnotherThread = [&]() { |
35 | Runner.runAsync(Name: "signal another thread", Action: SignalCurrentThread); |
36 | Runner.wait(); |
37 | }; |
38 | |
39 | bool Called; |
40 | { |
41 | ThreadCrashReporter ScopedReporter([&Called]() { Called = true; }); |
42 | // Check handler gets called when a signal gets delivered to the current |
43 | // thread. |
44 | Called = false; |
45 | SignalCurrentThread(); |
46 | EXPECT_TRUE(Called); |
47 | |
48 | // Check handler does not get called when another thread gets signalled. |
49 | Called = false; |
50 | SignalAnotherThread(); |
51 | EXPECT_FALSE(Called); |
52 | } |
53 | // Check handler does not get called when the reporter object goes out of |
54 | // scope. |
55 | Called = false; |
56 | SignalCurrentThread(); |
57 | EXPECT_FALSE(Called); |
58 | |
59 | std::string Order = ""; |
60 | { |
61 | ThreadCrashReporter ScopedReporter([&Order] { Order.push_back(c: 'a'); }); |
62 | { |
63 | ThreadCrashReporter ScopedReporter([&Order] { Order.push_back(c: 'b'); }); |
64 | SignalCurrentThread(); |
65 | } |
66 | // Check that handlers are called in LIFO order. |
67 | EXPECT_EQ(Order, "ba"); |
68 | |
69 | // Check that current handler is the only one after the nested scope is |
70 | // over. |
71 | SignalCurrentThread(); |
72 | EXPECT_EQ(Order, "baa"); |
73 | } |
74 | } |
75 | |
76 | } // namespace |
77 | } // namespace clangd |
78 | } // namespace clang |
79 |