Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lldb / unittests / Host / MainLoopTest.cpp
blob4084e90782fd5d1f867249669f45768e7628088b
1 //===-- MainLoopTest.cpp --------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
9 #include "lldb/Host/MainLoop.h"
10 #include "TestingSupport/SubsystemRAII.h"
11 #include "lldb/Host/ConnectionFileDescriptor.h"
12 #include "lldb/Host/FileSystem.h"
13 #include "lldb/Host/PseudoTerminal.h"
14 #include "lldb/Host/common/TCPSocket.h"
15 #include "llvm/Testing/Support/Error.h"
16 #include "gtest/gtest.h"
17 #include <future>
19 using namespace lldb_private;
21 namespace {
22 class MainLoopTest : public testing::Test {
23 public:
24 SubsystemRAII<FileSystem, Socket> subsystems;
26 void SetUp() override {
27 bool child_processes_inherit = false;
28 Status error;
29 std::unique_ptr<TCPSocket> listen_socket_up(
30 new TCPSocket(true, child_processes_inherit));
31 ASSERT_TRUE(error.Success());
32 error = listen_socket_up->Listen("localhost:0", 5);
33 ASSERT_TRUE(error.Success());
35 Socket *accept_socket;
36 std::unique_ptr<TCPSocket> connect_socket_up(
37 new TCPSocket(true, child_processes_inherit));
38 error = connect_socket_up->Connect(
39 llvm::formatv("localhost:{0}", listen_socket_up->GetLocalPortNumber())
40 .str());
41 ASSERT_TRUE(error.Success());
42 ASSERT_TRUE(listen_socket_up->Accept(accept_socket).Success());
44 callback_count = 0;
45 socketpair[0] = std::move(connect_socket_up);
46 socketpair[1].reset(accept_socket);
49 void TearDown() override {
50 socketpair[0].reset();
51 socketpair[1].reset();
54 protected:
55 MainLoop::Callback make_callback() {
56 return [&](MainLoopBase &loop) {
57 ++callback_count;
58 loop.RequestTermination();
61 std::shared_ptr<Socket> socketpair[2];
62 unsigned callback_count;
64 } // namespace
66 TEST_F(MainLoopTest, ReadObject) {
67 char X = 'X';
68 size_t len = sizeof(X);
69 ASSERT_TRUE(socketpair[0]->Write(&X, len).Success());
71 MainLoop loop;
73 Status error;
74 auto handle = loop.RegisterReadObject(socketpair[1], make_callback(), error);
75 ASSERT_TRUE(error.Success());
76 ASSERT_TRUE(handle);
77 ASSERT_TRUE(loop.Run().Success());
78 ASSERT_EQ(1u, callback_count);
81 TEST_F(MainLoopTest, TerminatesImmediately) {
82 char X = 'X';
83 size_t len = sizeof(X);
84 ASSERT_TRUE(socketpair[0]->Write(&X, len).Success());
85 ASSERT_TRUE(socketpair[1]->Write(&X, len).Success());
87 MainLoop loop;
88 Status error;
89 auto handle0 = loop.RegisterReadObject(socketpair[0], make_callback(), error);
90 ASSERT_TRUE(error.Success());
91 auto handle1 = loop.RegisterReadObject(socketpair[1], make_callback(), error);
92 ASSERT_TRUE(error.Success());
94 ASSERT_TRUE(loop.Run().Success());
95 ASSERT_EQ(1u, callback_count);
98 TEST_F(MainLoopTest, PendingCallback) {
99 char X = 'X';
100 size_t len = sizeof(X);
101 ASSERT_TRUE(socketpair[0]->Write(&X, len).Success());
103 MainLoop loop;
104 Status error;
105 auto handle = loop.RegisterReadObject(
106 socketpair[1],
107 [&](MainLoopBase &loop) {
108 // Both callbacks should be called before the loop terminates.
109 loop.AddPendingCallback(make_callback());
110 loop.AddPendingCallback(make_callback());
111 loop.RequestTermination();
113 error);
114 ASSERT_TRUE(error.Success());
115 ASSERT_TRUE(handle);
116 ASSERT_TRUE(loop.Run().Success());
117 ASSERT_EQ(2u, callback_count);
120 TEST_F(MainLoopTest, PendingCallbackCalledOnlyOnce) {
121 char X = 'X';
122 size_t len = sizeof(X);
123 ASSERT_TRUE(socketpair[0]->Write(&X, len).Success());
125 MainLoop loop;
126 Status error;
127 auto handle = loop.RegisterReadObject(
128 socketpair[1],
129 [&](MainLoopBase &loop) {
130 // Add one pending callback on the first iteration.
131 if (callback_count == 0) {
132 loop.AddPendingCallback([&](MainLoopBase &loop) {
133 callback_count++;
136 // Terminate the loop on second iteration.
137 if (callback_count++ >= 1)
138 loop.RequestTermination();
140 error);
141 ASSERT_TRUE(error.Success());
142 ASSERT_TRUE(handle);
143 ASSERT_TRUE(loop.Run().Success());
144 // 2 iterations of read callback + 1 call of pending callback.
145 ASSERT_EQ(3u, callback_count);
148 TEST_F(MainLoopTest, PendingCallbackTrigger) {
149 MainLoop loop;
150 std::promise<void> add_callback2;
151 bool callback1_called = false;
152 loop.AddPendingCallback([&](MainLoopBase &loop) {
153 callback1_called = true;
154 add_callback2.set_value();
156 Status error;
157 auto socket_handle = loop.RegisterReadObject(
158 socketpair[1], [](MainLoopBase &) {}, error);
159 ASSERT_TRUE(socket_handle);
160 ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
161 bool callback2_called = false;
162 std::thread callback2_adder([&]() {
163 add_callback2.get_future().get();
164 loop.AddPendingCallback([&](MainLoopBase &loop) {
165 callback2_called = true;
166 loop.RequestTermination();
169 ASSERT_THAT_ERROR(loop.Run().ToError(), llvm::Succeeded());
170 callback2_adder.join();
171 ASSERT_TRUE(callback1_called);
172 ASSERT_TRUE(callback2_called);
175 // Regression test for assertion failure if a lot of callbacks end up
176 // being queued after loop exits.
177 TEST_F(MainLoopTest, PendingCallbackAfterLoopExited) {
178 MainLoop loop;
179 Status error;
180 ASSERT_TRUE(loop.Run().Success());
181 // Try to fill the pipe buffer in.
182 for (int i = 0; i < 65536; ++i)
183 loop.AddPendingCallback([&](MainLoopBase &loop) {});
186 #ifdef LLVM_ON_UNIX
187 TEST_F(MainLoopTest, DetectsEOF) {
189 PseudoTerminal term;
190 ASSERT_THAT_ERROR(term.OpenFirstAvailablePrimary(O_RDWR), llvm::Succeeded());
191 ASSERT_THAT_ERROR(term.OpenSecondary(O_RDWR | O_NOCTTY), llvm::Succeeded());
192 auto conn = std::make_unique<ConnectionFileDescriptor>(
193 term.ReleasePrimaryFileDescriptor(), true);
195 Status error;
196 MainLoop loop;
197 auto handle =
198 loop.RegisterReadObject(conn->GetReadObject(), make_callback(), error);
199 ASSERT_TRUE(error.Success());
200 term.CloseSecondaryFileDescriptor();
202 ASSERT_TRUE(loop.Run().Success());
203 ASSERT_EQ(1u, callback_count);
206 TEST_F(MainLoopTest, Signal) {
207 MainLoop loop;
208 Status error;
210 auto handle = loop.RegisterSignal(SIGUSR1, make_callback(), error);
211 ASSERT_TRUE(error.Success());
212 kill(getpid(), SIGUSR1);
213 ASSERT_TRUE(loop.Run().Success());
214 ASSERT_EQ(1u, callback_count);
217 // Test that a signal which is not monitored by the MainLoop does not
218 // cause a premature exit.
219 TEST_F(MainLoopTest, UnmonitoredSignal) {
220 MainLoop loop;
221 Status error;
222 struct sigaction sa;
223 sa.sa_sigaction = [](int, siginfo_t *, void *) { };
224 sa.sa_flags = SA_SIGINFO; // important: no SA_RESTART
225 sigemptyset(&sa.sa_mask);
226 ASSERT_EQ(0, sigaction(SIGUSR2, &sa, nullptr));
228 auto handle = loop.RegisterSignal(SIGUSR1, make_callback(), error);
229 ASSERT_TRUE(error.Success());
230 kill(getpid(), SIGUSR2);
231 kill(getpid(), SIGUSR1);
232 ASSERT_TRUE(loop.Run().Success());
233 ASSERT_EQ(1u, callback_count);
236 // Test that two callbacks can be registered for the same signal
237 // and unregistered independently.
238 TEST_F(MainLoopTest, TwoSignalCallbacks) {
239 MainLoop loop;
240 Status error;
241 unsigned callback2_count = 0;
242 unsigned callback3_count = 0;
244 auto handle = loop.RegisterSignal(SIGUSR1, make_callback(), error);
245 ASSERT_TRUE(error.Success());
248 // Run a single iteration with two callbacks enabled.
249 auto handle2 = loop.RegisterSignal(
250 SIGUSR1, [&](MainLoopBase &loop) { ++callback2_count; }, error);
251 ASSERT_TRUE(error.Success());
253 kill(getpid(), SIGUSR1);
254 ASSERT_TRUE(loop.Run().Success());
255 ASSERT_EQ(1u, callback_count);
256 ASSERT_EQ(1u, callback2_count);
257 ASSERT_EQ(0u, callback3_count);
261 // Make sure that remove + add new works.
262 auto handle3 = loop.RegisterSignal(
263 SIGUSR1, [&](MainLoopBase &loop) { ++callback3_count; }, error);
264 ASSERT_TRUE(error.Success());
266 kill(getpid(), SIGUSR1);
267 ASSERT_TRUE(loop.Run().Success());
268 ASSERT_EQ(2u, callback_count);
269 ASSERT_EQ(1u, callback2_count);
270 ASSERT_EQ(1u, callback3_count);
273 // Both extra callbacks should be unregistered now.
274 kill(getpid(), SIGUSR1);
275 ASSERT_TRUE(loop.Run().Success());
276 ASSERT_EQ(3u, callback_count);
277 ASSERT_EQ(1u, callback2_count);
278 ASSERT_EQ(1u, callback3_count);
280 #endif