Skip to content

Commit 4353530

Browse files
authored
[lldb/windows] Reset MainLoop events after handling them (#107061)
This prevents the callback function from being called in a busy loop. Discovered by @slydiman on #106955.
1 parent a5f03b4 commit 4353530

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

lldb/source/Host/windows/MainLoopWindows.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ Status MainLoopWindows::Run() {
125125

126126
if (*signaled_event < m_read_fds.size()) {
127127
auto &KV = *std::next(m_read_fds.begin(), *signaled_event);
128+
WSAResetEvent(KV.second.event);
128129
ProcessReadObject(KV.first);
129130
} else {
130131
assert(*signaled_event == m_read_fds.size());

lldb/unittests/Host/MainLoopTest.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "llvm/Testing/Support/Error.h"
1616
#include "gtest/gtest.h"
1717
#include <future>
18+
#include <thread>
1819

1920
using namespace lldb_private;
2021

@@ -78,6 +79,44 @@ TEST_F(MainLoopTest, ReadObject) {
7879
ASSERT_EQ(1u, callback_count);
7980
}
8081

82+
TEST_F(MainLoopTest, NoSpuriousReads) {
83+
// Write one byte into the socket.
84+
char X = 'X';
85+
size_t len = sizeof(X);
86+
ASSERT_TRUE(socketpair[0]->Write(&X, len).Success());
87+
88+
MainLoop loop;
89+
90+
Status error;
91+
auto handle = loop.RegisterReadObject(
92+
socketpair[1],
93+
[this](MainLoopBase &) {
94+
if (callback_count == 0) {
95+
// Read the byte back the first time we're called. After that, the
96+
// socket is empty, and we should not be called anymore.
97+
char X;
98+
size_t len = sizeof(X);
99+
EXPECT_THAT_ERROR(socketpair[1]->Read(&X, len).ToError(),
100+
llvm::Succeeded());
101+
EXPECT_EQ(len, sizeof(X));
102+
}
103+
++callback_count;
104+
},
105+
error);
106+
ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
107+
// Terminate the loop after one second.
108+
std::thread terminate_thread([&loop] {
109+
std::this_thread::sleep_for(std::chrono::seconds(1));
110+
loop.AddPendingCallback(
111+
[](MainLoopBase &loop) { loop.RequestTermination(); });
112+
});
113+
ASSERT_THAT_ERROR(loop.Run().ToError(), llvm::Succeeded());
114+
terminate_thread.join();
115+
116+
// Make sure the callback was called only once.
117+
ASSERT_EQ(1u, callback_count);
118+
}
119+
81120
TEST_F(MainLoopTest, TerminatesImmediately) {
82121
char X = 'X';
83122
size_t len = sizeof(X);

0 commit comments

Comments
 (0)