Skip to content

Commit 98b419c

Browse files
authored
[lldb] Don't exit the main loop when in runs out of things to listen on (#112565)
This behavior made sense in the beginning as the class was completely single threaded, so if the source count ever reached zero, there was no way to add new ones. In https://reviews.llvm.org/D131160, the class gained the ability to add events (callbacks) from other threads, which means that is no longer the case (and indeed, one possible use case for this class -- acting as a sort of arbiter for multiple threads wanting to run code while making sure it runs serially -- has this class sit in an empty Run call most of the time). I'm not aware of us having a use for such a thing right now, but one of my tests in another patch turned into something similar by accident. Another problem with the current approach is that, in a distributed/dynamic setup (multiple things using the main loop without a clear coordinator), one can never be sure whether unregistering a specific event will terminate the loop (it depends on whether there are other listeners). We had this problem in lldb-platform.cpp, where we had to add an additional layer of synchronization to avoid premature termination. We can remove this if we can rely on the loop terminating only when we tell it to.
1 parent 4897fc4 commit 98b419c

File tree

4 files changed

+21
-33
lines changed

4 files changed

+21
-33
lines changed

lldb/source/Host/posix/MainLoopPosix.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,7 @@ Status MainLoopPosix::Run() {
365365
Status error;
366366
RunImpl impl(*this);
367367

368-
// run until termination or until we run out of things to listen to
369-
// (m_read_fds will always contain m_trigger_pipe fd, so check for > 1)
370-
while (!m_terminate_request &&
371-
(m_read_fds.size() > 1 || !m_signals.empty())) {
368+
while (!m_terminate_request) {
372369
error = impl.Poll();
373370
if (error.Fail())
374371
return error;

lldb/source/Host/windows/MainLoopWindows.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,7 @@ Status MainLoopWindows::Run() {
116116

117117
Status error;
118118

119-
// run until termination or until we run out of things to listen to
120-
while (!m_terminate_request && !m_read_fds.empty()) {
121-
119+
while (!m_terminate_request) {
122120
llvm::Expected<size_t> signaled_event = Poll();
123121
if (!signaled_event)
124122
return Status::FromError(signaled_event.takeError());

lldb/tools/lldb-server/lldb-platform.cpp

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,7 @@ static void client_handle(GDBRemoteCommunicationServerPlatform &platform,
260260
static Status spawn_process(const char *progname, const Socket *conn_socket,
261261
uint16_t gdb_port, const lldb_private::Args &args,
262262
const std::string &log_file,
263-
const StringRef log_channels, MainLoop &main_loop,
264-
std::promise<void> &child_exited) {
263+
const StringRef log_channels, MainLoop &main_loop) {
265264
Status error;
266265
SharedSocket shared_socket(conn_socket, error);
267266
if (error.Fail())
@@ -301,12 +300,10 @@ static Status spawn_process(const char *progname, const Socket *conn_socket,
301300
if (g_server)
302301
launch_info.SetMonitorProcessCallback([](lldb::pid_t, int, int) {});
303302
else
304-
launch_info.SetMonitorProcessCallback(
305-
[&child_exited, &main_loop](lldb::pid_t, int, int) {
306-
main_loop.AddPendingCallback(
307-
[](MainLoopBase &loop) { loop.RequestTermination(); });
308-
child_exited.set_value();
309-
});
303+
launch_info.SetMonitorProcessCallback([&main_loop](lldb::pid_t, int, int) {
304+
main_loop.AddPendingCallback(
305+
[](MainLoopBase &loop) { loop.RequestTermination(); });
306+
});
310307

311308
// Copy the current environment.
312309
launch_info.GetEnvironment() = Host::GetEnvironment();
@@ -550,27 +547,24 @@ int main_platform(int argc, char *argv[]) {
550547
return socket_error;
551548
}
552549

553-
std::promise<void> child_exited;
554550
MainLoop main_loop;
555551
{
556552
llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> platform_handles =
557553
platform_sock->Accept(
558554
main_loop, [progname, gdbserver_port, &inferior_arguments, log_file,
559-
log_channels, &main_loop, &child_exited,
555+
log_channels, &main_loop,
560556
&platform_handles](std::unique_ptr<Socket> sock_up) {
561557
printf("Connection established.\n");
562-
Status error = spawn_process(
563-
progname, sock_up.get(), gdbserver_port, inferior_arguments,
564-
log_file, log_channels, main_loop, child_exited);
558+
Status error = spawn_process(progname, sock_up.get(),
559+
gdbserver_port, inferior_arguments,
560+
log_file, log_channels, main_loop);
565561
if (error.Fail()) {
566562
Log *log = GetLog(LLDBLog::Platform);
567563
LLDB_LOGF(log, "spawn_process failed: %s", error.AsCString());
568564
WithColor::error()
569565
<< "spawn_process failed: " << error.AsCString() << "\n";
570-
if (!g_server) {
566+
if (!g_server)
571567
main_loop.RequestTermination();
572-
child_exited.set_value();
573-
}
574568
}
575569
if (!g_server)
576570
platform_handles->clear();
@@ -592,7 +586,6 @@ int main_platform(int argc, char *argv[]) {
592586

593587
main_loop.Run();
594588
}
595-
child_exited.get_future().get();
596589

597590
fprintf(stderr, "lldb-server exiting...\n");
598591

lldb/unittests/Host/MainLoopTest.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,6 @@ TEST_F(MainLoopTest, PendingCallbackTrigger) {
194194
add_callback2.set_value();
195195
});
196196
Status error;
197-
auto socket_handle = loop.RegisterReadObject(
198-
socketpair[1], [](MainLoopBase &) {}, error);
199-
ASSERT_TRUE(socket_handle);
200197
ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
201198
bool callback2_called = false;
202199
std::thread callback2_adder([&]() {
@@ -212,15 +209,18 @@ TEST_F(MainLoopTest, PendingCallbackTrigger) {
212209
ASSERT_TRUE(callback2_called);
213210
}
214211

215-
// Regression test for assertion failure if a lot of callbacks end up
216-
// being queued after loop exits.
217-
TEST_F(MainLoopTest, PendingCallbackAfterLoopExited) {
212+
TEST_F(MainLoopTest, ManyPendingCallbacks) {
218213
MainLoop loop;
219214
Status error;
220-
ASSERT_TRUE(loop.Run().Success());
221-
// Try to fill the pipe buffer in.
215+
// Try to fill up the pipe buffer and make sure bad things don't happen. This
216+
// is a regression test for the case where writing to the interrupt pipe
217+
// caused a deadlock when the pipe filled up (either because the main loop was
218+
// not running, because it was slow, or because it was busy/blocked doing
219+
// something else).
222220
for (int i = 0; i < 65536; ++i)
223-
loop.AddPendingCallback([&](MainLoopBase &loop) {});
221+
loop.AddPendingCallback(
222+
[&](MainLoopBase &loop) { loop.RequestTermination(); });
223+
ASSERT_TRUE(loop.Run().Success());
224224
}
225225

226226
#ifdef LLVM_ON_UNIX

0 commit comments

Comments
 (0)