1 //===-- MainLoopTest.cpp --------------------------------------------------===//
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
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/Config/llvm-config.h" // for LLVM_ON_UNIX
16 #include "llvm/Testing/Support/Error.h"
17 #include "gtest/gtest.h"
22 using namespace lldb_private
;
25 class MainLoopTest
: public testing::Test
{
27 SubsystemRAII
<FileSystem
, Socket
> subsystems
;
29 void SetUp() override
{
30 bool child_processes_inherit
= false;
32 std::unique_ptr
<TCPSocket
> listen_socket_up(
33 new TCPSocket(true, child_processes_inherit
));
34 ASSERT_TRUE(error
.Success());
35 error
= listen_socket_up
->Listen("localhost:0", 5);
36 ASSERT_TRUE(error
.Success());
38 Socket
*accept_socket
;
39 std::unique_ptr
<TCPSocket
> connect_socket_up(
40 new TCPSocket(true, child_processes_inherit
));
41 error
= connect_socket_up
->Connect(
42 llvm::formatv("localhost:{0}", listen_socket_up
->GetLocalPortNumber())
44 ASSERT_TRUE(error
.Success());
45 ASSERT_TRUE(listen_socket_up
->Accept(accept_socket
).Success());
48 socketpair
[0] = std::move(connect_socket_up
);
49 socketpair
[1].reset(accept_socket
);
52 void TearDown() override
{
53 socketpair
[0].reset();
54 socketpair
[1].reset();
58 MainLoop::Callback
make_callback() {
59 return [&](MainLoopBase
&loop
) {
61 loop
.RequestTermination();
64 std::shared_ptr
<Socket
> socketpair
[2];
65 unsigned callback_count
;
69 TEST_F(MainLoopTest
, ReadObject
) {
71 size_t len
= sizeof(X
);
72 ASSERT_TRUE(socketpair
[0]->Write(&X
, len
).Success());
77 auto handle
= loop
.RegisterReadObject(socketpair
[1], make_callback(), error
);
78 ASSERT_TRUE(error
.Success());
80 ASSERT_TRUE(loop
.Run().Success());
81 ASSERT_EQ(1u, callback_count
);
84 TEST_F(MainLoopTest
, NoSpuriousReads
) {
85 // Write one byte into the socket.
87 size_t len
= sizeof(X
);
88 ASSERT_TRUE(socketpair
[0]->Write(&X
, len
).Success());
93 auto handle
= loop
.RegisterReadObject(
95 [this](MainLoopBase
&) {
96 if (callback_count
== 0) {
97 // Read the byte back the first time we're called. After that, the
98 // socket is empty, and we should not be called anymore.
100 size_t len
= sizeof(X
);
101 EXPECT_THAT_ERROR(socketpair
[1]->Read(&X
, len
).ToError(),
103 EXPECT_EQ(len
, sizeof(X
));
108 ASSERT_THAT_ERROR(error
.ToError(), llvm::Succeeded());
109 // Terminate the loop after one second.
110 loop
.AddCallback([](MainLoopBase
&loop
) { loop
.RequestTermination(); },
111 std::chrono::seconds(1));
112 ASSERT_THAT_ERROR(loop
.Run().ToError(), llvm::Succeeded());
114 // Make sure the callback was called only once.
115 ASSERT_EQ(1u, callback_count
);
118 TEST_F(MainLoopTest
, TerminatesImmediately
) {
120 size_t len
= sizeof(X
);
121 ASSERT_TRUE(socketpair
[0]->Write(&X
, len
).Success());
122 ASSERT_TRUE(socketpair
[1]->Write(&X
, len
).Success());
126 auto handle0
= loop
.RegisterReadObject(socketpair
[0], make_callback(), error
);
127 ASSERT_TRUE(error
.Success());
128 auto handle1
= loop
.RegisterReadObject(socketpair
[1], make_callback(), error
);
129 ASSERT_TRUE(error
.Success());
131 ASSERT_TRUE(loop
.Run().Success());
132 ASSERT_EQ(1u, callback_count
);
135 TEST_F(MainLoopTest
, PendingCallback
) {
137 size_t len
= sizeof(X
);
138 ASSERT_TRUE(socketpair
[0]->Write(&X
, len
).Success());
142 auto handle
= loop
.RegisterReadObject(
144 [&](MainLoopBase
&loop
) {
145 // Both callbacks should be called before the loop terminates.
146 loop
.AddPendingCallback(make_callback());
147 loop
.AddPendingCallback(make_callback());
148 loop
.RequestTermination();
151 ASSERT_TRUE(error
.Success());
153 ASSERT_TRUE(loop
.Run().Success());
154 ASSERT_EQ(2u, callback_count
);
157 TEST_F(MainLoopTest
, PendingCallbackCalledOnlyOnce
) {
159 size_t len
= sizeof(X
);
160 ASSERT_TRUE(socketpair
[0]->Write(&X
, len
).Success());
164 auto handle
= loop
.RegisterReadObject(
166 [&](MainLoopBase
&loop
) {
167 // Add one pending callback on the first iteration.
168 if (callback_count
== 0) {
169 loop
.AddPendingCallback([&](MainLoopBase
&loop
) {
173 // Terminate the loop on second iteration.
174 if (callback_count
++ >= 1)
175 loop
.RequestTermination();
178 ASSERT_TRUE(error
.Success());
180 ASSERT_TRUE(loop
.Run().Success());
181 // 2 iterations of read callback + 1 call of pending callback.
182 ASSERT_EQ(3u, callback_count
);
185 TEST_F(MainLoopTest
, PendingCallbackTrigger
) {
187 std::promise
<void> add_callback2
;
188 bool callback1_called
= false;
189 loop
.AddPendingCallback([&](MainLoopBase
&loop
) {
190 callback1_called
= true;
191 add_callback2
.set_value();
194 ASSERT_THAT_ERROR(error
.ToError(), llvm::Succeeded());
195 bool callback2_called
= false;
196 std::thread
callback2_adder([&]() {
197 add_callback2
.get_future().get();
198 loop
.AddPendingCallback([&](MainLoopBase
&loop
) {
199 callback2_called
= true;
200 loop
.RequestTermination();
203 ASSERT_THAT_ERROR(loop
.Run().ToError(), llvm::Succeeded());
204 callback2_adder
.join();
205 ASSERT_TRUE(callback1_called
);
206 ASSERT_TRUE(callback2_called
);
209 TEST_F(MainLoopTest
, ManyPendingCallbacks
) {
212 // Try to fill up the pipe buffer and make sure bad things don't happen. This
213 // is a regression test for the case where writing to the interrupt pipe
214 // caused a deadlock when the pipe filled up (either because the main loop was
215 // not running, because it was slow, or because it was busy/blocked doing
217 for (int i
= 0; i
< 65536; ++i
)
218 loop
.AddPendingCallback(
219 [&](MainLoopBase
&loop
) { loop
.RequestTermination(); });
220 ASSERT_TRUE(loop
.Run().Success());
223 TEST_F(MainLoopTest
, CallbackWithTimeout
) {
225 loop
.AddCallback([](MainLoopBase
&loop
) { loop
.RequestTermination(); },
226 std::chrono::seconds(2));
227 auto start
= std::chrono::steady_clock::now();
228 ASSERT_THAT_ERROR(loop
.Run().takeError(), llvm::Succeeded());
229 EXPECT_GE(std::chrono::steady_clock::now() - start
, std::chrono::seconds(2));
232 TEST_F(MainLoopTest
, TimedCallbacksRunInOrder
) {
234 auto start
= std::chrono::steady_clock::now();
235 std::chrono::milliseconds
epsilon(10);
236 std::vector
<int> order
;
237 auto add_cb
= [&](int id
) {
238 loop
.AddCallback([&order
, id
](MainLoopBase
&) { order
.push_back(id
); },
239 start
+ id
* epsilon
);
245 loop
.AddCallback([](MainLoopBase
&loop
) { loop
.RequestTermination(); },
246 start
+ 5 * epsilon
);
247 ASSERT_THAT_ERROR(loop
.Run().takeError(), llvm::Succeeded());
248 EXPECT_GE(std::chrono::steady_clock::now() - start
, 5 * epsilon
);
249 ASSERT_THAT(order
, testing::ElementsAre(1, 2, 3, 4));
252 TEST_F(MainLoopTest
, TimedCallbackShortensSleep
) {
254 auto start
= std::chrono::steady_clock::now();
255 bool long_callback_called
= false;
257 [&](MainLoopBase
&loop
) {
258 long_callback_called
= true;
259 loop
.RequestTermination();
261 std::chrono::seconds(30));
262 std::future
<Status
> async_run
=
263 std::async(std::launch::async
, &MainLoop::Run
, std::ref(loop
));
264 std::this_thread::sleep_for(std::chrono::milliseconds(100));
265 bool short_callback_called
= false;
267 [&](MainLoopBase
&loop
) {
268 short_callback_called
= true;
269 loop
.RequestTermination();
271 std::chrono::seconds(1));
272 ASSERT_THAT_ERROR(async_run
.get().takeError(), llvm::Succeeded());
273 EXPECT_LT(std::chrono::steady_clock::now() - start
, std::chrono::seconds(10));
274 EXPECT_TRUE(short_callback_called
);
275 EXPECT_FALSE(long_callback_called
);
279 TEST_F(MainLoopTest
, DetectsEOF
) {
282 ASSERT_THAT_ERROR(term
.OpenFirstAvailablePrimary(O_RDWR
), llvm::Succeeded());
283 ASSERT_THAT_ERROR(term
.OpenSecondary(O_RDWR
| O_NOCTTY
), llvm::Succeeded());
284 auto conn
= std::make_unique
<ConnectionFileDescriptor
>(
285 term
.ReleasePrimaryFileDescriptor(), true);
290 loop
.RegisterReadObject(conn
->GetReadObject(), make_callback(), error
);
291 ASSERT_TRUE(error
.Success());
292 term
.CloseSecondaryFileDescriptor();
294 ASSERT_TRUE(loop
.Run().Success());
295 ASSERT_EQ(1u, callback_count
);
298 TEST_F(MainLoopTest
, Signal
) {
302 auto handle
= loop
.RegisterSignal(SIGUSR1
, make_callback(), error
);
303 ASSERT_TRUE(error
.Success());
304 kill(getpid(), SIGUSR1
);
305 ASSERT_TRUE(loop
.Run().Success());
306 ASSERT_EQ(1u, callback_count
);
309 TEST_F(MainLoopTest
, SignalOnOtherThread
) {
313 auto handle
= loop
.RegisterSignal(SIGUSR1
, make_callback(), error
);
314 ASSERT_TRUE(error
.Success());
315 std::thread([] { pthread_kill(pthread_self(), SIGUSR1
); }).join();
316 ASSERT_TRUE(loop
.Run().Success());
317 ASSERT_EQ(1u, callback_count
);
320 // Test that a signal which is not monitored by the MainLoop does not
321 // cause a premature exit.
322 TEST_F(MainLoopTest
, UnmonitoredSignal
) {
326 sa
.sa_sigaction
= [](int, siginfo_t
*, void *) { };
327 sa
.sa_flags
= SA_SIGINFO
; // important: no SA_RESTART
328 sigemptyset(&sa
.sa_mask
);
329 ASSERT_EQ(0, sigaction(SIGUSR2
, &sa
, nullptr));
331 auto handle
= loop
.RegisterSignal(SIGUSR1
, make_callback(), error
);
332 ASSERT_TRUE(error
.Success());
333 kill(getpid(), SIGUSR2
);
334 kill(getpid(), SIGUSR1
);
335 ASSERT_TRUE(loop
.Run().Success());
336 ASSERT_EQ(1u, callback_count
);
339 // Test that two callbacks can be registered for the same signal
340 // and unregistered independently.
341 TEST_F(MainLoopTest
, TwoSignalCallbacks
) {
344 unsigned callback2_count
= 0;
345 unsigned callback3_count
= 0;
347 auto handle
= loop
.RegisterSignal(SIGUSR1
, make_callback(), error
);
348 ASSERT_TRUE(error
.Success());
351 // Run a single iteration with two callbacks enabled.
352 auto handle2
= loop
.RegisterSignal(
353 SIGUSR1
, [&](MainLoopBase
&loop
) { ++callback2_count
; }, error
);
354 ASSERT_TRUE(error
.Success());
356 kill(getpid(), SIGUSR1
);
357 ASSERT_TRUE(loop
.Run().Success());
358 ASSERT_EQ(1u, callback_count
);
359 ASSERT_EQ(1u, callback2_count
);
360 ASSERT_EQ(0u, callback3_count
);
364 // Make sure that remove + add new works.
365 auto handle3
= loop
.RegisterSignal(
366 SIGUSR1
, [&](MainLoopBase
&loop
) { ++callback3_count
; }, error
);
367 ASSERT_TRUE(error
.Success());
369 kill(getpid(), SIGUSR1
);
370 ASSERT_TRUE(loop
.Run().Success());
371 ASSERT_EQ(2u, callback_count
);
372 ASSERT_EQ(1u, callback2_count
);
373 ASSERT_EQ(1u, callback3_count
);
376 // Both extra callbacks should be unregistered now.
377 kill(getpid(), SIGUSR1
);
378 ASSERT_TRUE(loop
.Run().Success());
379 ASSERT_EQ(3u, callback_count
);
380 ASSERT_EQ(1u, callback2_count
);
381 ASSERT_EQ(1u, callback3_count
);