aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Labath <pavel@labath.sk>2024-10-17 17:29:38 +0200
committerGitHub <noreply@github.com>2024-10-17 17:29:38 +0200
commit98b419ca7688aa2823df1e87f58051aaa8d9c37f (patch)
tree1510f532a03fc9dfda1d3c635b89d29488708e3d
parent4897fc44a918b8da886d48082b6cf004cf3ffe0b (diff)
downloadllvm-98b419ca7688aa2823df1e87f58051aaa8d9c37f.zip
llvm-98b419ca7688aa2823df1e87f58051aaa8d9c37f.tar.gz
llvm-98b419ca7688aa2823df1e87f58051aaa8d9c37f.tar.bz2
[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.
-rw-r--r--lldb/source/Host/posix/MainLoopPosix.cpp5
-rw-r--r--lldb/source/Host/windows/MainLoopWindows.cpp4
-rw-r--r--lldb/tools/lldb-server/lldb-platform.cpp27
-rw-r--r--lldb/unittests/Host/MainLoopTest.cpp18
4 files changed, 21 insertions, 33 deletions
diff --git a/lldb/source/Host/posix/MainLoopPosix.cpp b/lldb/source/Host/posix/MainLoopPosix.cpp
index 816581e..6f8eaa5 100644
--- a/lldb/source/Host/posix/MainLoopPosix.cpp
+++ b/lldb/source/Host/posix/MainLoopPosix.cpp
@@ -365,10 +365,7 @@ Status MainLoopPosix::Run() {
Status error;
RunImpl impl(*this);
- // run until termination or until we run out of things to listen to
- // (m_read_fds will always contain m_trigger_pipe fd, so check for > 1)
- while (!m_terminate_request &&
- (m_read_fds.size() > 1 || !m_signals.empty())) {
+ while (!m_terminate_request) {
error = impl.Poll();
if (error.Fail())
return error;
diff --git a/lldb/source/Host/windows/MainLoopWindows.cpp b/lldb/source/Host/windows/MainLoopWindows.cpp
index 88d9295..c9aa6d3 100644
--- a/lldb/source/Host/windows/MainLoopWindows.cpp
+++ b/lldb/source/Host/windows/MainLoopWindows.cpp
@@ -116,9 +116,7 @@ Status MainLoopWindows::Run() {
Status error;
- // run until termination or until we run out of things to listen to
- while (!m_terminate_request && !m_read_fds.empty()) {
-
+ while (!m_terminate_request) {
llvm::Expected<size_t> signaled_event = Poll();
if (!signaled_event)
return Status::FromError(signaled_event.takeError());
diff --git a/lldb/tools/lldb-server/lldb-platform.cpp b/lldb/tools/lldb-server/lldb-platform.cpp
index 2ef7805..735a558 100644
--- a/lldb/tools/lldb-server/lldb-platform.cpp
+++ b/lldb/tools/lldb-server/lldb-platform.cpp
@@ -260,8 +260,7 @@ static void client_handle(GDBRemoteCommunicationServerPlatform &platform,
static Status spawn_process(const char *progname, const Socket *conn_socket,
uint16_t gdb_port, const lldb_private::Args &args,
const std::string &log_file,
- const StringRef log_channels, MainLoop &main_loop,
- std::promise<void> &child_exited) {
+ const StringRef log_channels, MainLoop &main_loop) {
Status error;
SharedSocket shared_socket(conn_socket, error);
if (error.Fail())
@@ -301,12 +300,10 @@ static Status spawn_process(const char *progname, const Socket *conn_socket,
if (g_server)
launch_info.SetMonitorProcessCallback([](lldb::pid_t, int, int) {});
else
- launch_info.SetMonitorProcessCallback(
- [&child_exited, &main_loop](lldb::pid_t, int, int) {
- main_loop.AddPendingCallback(
- [](MainLoopBase &loop) { loop.RequestTermination(); });
- child_exited.set_value();
- });
+ launch_info.SetMonitorProcessCallback([&main_loop](lldb::pid_t, int, int) {
+ main_loop.AddPendingCallback(
+ [](MainLoopBase &loop) { loop.RequestTermination(); });
+ });
// Copy the current environment.
launch_info.GetEnvironment() = Host::GetEnvironment();
@@ -550,27 +547,24 @@ int main_platform(int argc, char *argv[]) {
return socket_error;
}
- std::promise<void> child_exited;
MainLoop main_loop;
{
llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> platform_handles =
platform_sock->Accept(
main_loop, [progname, gdbserver_port, &inferior_arguments, log_file,
- log_channels, &main_loop, &child_exited,
+ log_channels, &main_loop,
&platform_handles](std::unique_ptr<Socket> sock_up) {
printf("Connection established.\n");
- Status error = spawn_process(
- progname, sock_up.get(), gdbserver_port, inferior_arguments,
- log_file, log_channels, main_loop, child_exited);
+ Status error = spawn_process(progname, sock_up.get(),
+ gdbserver_port, inferior_arguments,
+ log_file, log_channels, main_loop);
if (error.Fail()) {
Log *log = GetLog(LLDBLog::Platform);
LLDB_LOGF(log, "spawn_process failed: %s", error.AsCString());
WithColor::error()
<< "spawn_process failed: " << error.AsCString() << "\n";
- if (!g_server) {
+ if (!g_server)
main_loop.RequestTermination();
- child_exited.set_value();
- }
}
if (!g_server)
platform_handles->clear();
@@ -592,7 +586,6 @@ int main_platform(int argc, char *argv[]) {
main_loop.Run();
}
- child_exited.get_future().get();
fprintf(stderr, "lldb-server exiting...\n");
diff --git a/lldb/unittests/Host/MainLoopTest.cpp b/lldb/unittests/Host/MainLoopTest.cpp
index b8417c9..4688d4f 100644
--- a/lldb/unittests/Host/MainLoopTest.cpp
+++ b/lldb/unittests/Host/MainLoopTest.cpp
@@ -194,9 +194,6 @@ TEST_F(MainLoopTest, PendingCallbackTrigger) {
add_callback2.set_value();
});
Status error;
- auto socket_handle = loop.RegisterReadObject(
- socketpair[1], [](MainLoopBase &) {}, error);
- ASSERT_TRUE(socket_handle);
ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
bool callback2_called = false;
std::thread callback2_adder([&]() {
@@ -212,15 +209,18 @@ TEST_F(MainLoopTest, PendingCallbackTrigger) {
ASSERT_TRUE(callback2_called);
}
-// Regression test for assertion failure if a lot of callbacks end up
-// being queued after loop exits.
-TEST_F(MainLoopTest, PendingCallbackAfterLoopExited) {
+TEST_F(MainLoopTest, ManyPendingCallbacks) {
MainLoop loop;
Status error;
- ASSERT_TRUE(loop.Run().Success());
- // Try to fill the pipe buffer in.
+ // Try to fill up the pipe buffer and make sure bad things don't happen. This
+ // is a regression test for the case where writing to the interrupt pipe
+ // caused a deadlock when the pipe filled up (either because the main loop was
+ // not running, because it was slow, or because it was busy/blocked doing
+ // something else).
for (int i = 0; i < 65536; ++i)
- loop.AddPendingCallback([&](MainLoopBase &loop) {});
+ loop.AddPendingCallback(
+ [&](MainLoopBase &loop) { loop.RequestTermination(); });
+ ASSERT_TRUE(loop.Run().Success());
}
#ifdef LLVM_ON_UNIX