[Lldb-commits] [lldb] [lldb/windows] Reset MainLoop events after handling them (PR #107061)

Pavel Labath via lldb-commits lldb-commits at lists.llvm.org
Tue Sep 3 01:57:38 PDT 2024


https://github.com/labath created https://github.com/llvm/llvm-project/pull/107061

This prevents the callback function from being called in a busy loop. Discovered by @slydiman on #106955.

>From 0a5ea38fe79ed5433535a3bc3bf895385c9d96e9 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Tue, 3 Sep 2024 10:45:10 +0200
Subject: [PATCH] [lldb/windows] Reset MainLoop events after handling them

This prevents the callback function from being called in a busy loop.
Discovered by @slydiman on #106955.
---
 lldb/source/Host/windows/MainLoopWindows.cpp |  1 +
 lldb/unittests/Host/MainLoopTest.cpp         | 39 ++++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/lldb/source/Host/windows/MainLoopWindows.cpp b/lldb/source/Host/windows/MainLoopWindows.cpp
index d34972a93f5850..551e73e6904ae7 100644
--- a/lldb/source/Host/windows/MainLoopWindows.cpp
+++ b/lldb/source/Host/windows/MainLoopWindows.cpp
@@ -125,6 +125,7 @@ Status MainLoopWindows::Run() {
 
     if (*signaled_event < m_read_fds.size()) {
       auto &KV = *std::next(m_read_fds.begin(), *signaled_event);
+      WSAResetEvent(KV.second.event);
       ProcessReadObject(KV.first);
     } else {
       assert(*signaled_event == m_read_fds.size());
diff --git a/lldb/unittests/Host/MainLoopTest.cpp b/lldb/unittests/Host/MainLoopTest.cpp
index 4084e90782fd5d..5843faeab505ee 100644
--- a/lldb/unittests/Host/MainLoopTest.cpp
+++ b/lldb/unittests/Host/MainLoopTest.cpp
@@ -15,6 +15,7 @@
 #include "llvm/Testing/Support/Error.h"
 #include "gtest/gtest.h"
 #include <future>
+#include <thread>
 
 using namespace lldb_private;
 
@@ -78,6 +79,44 @@ TEST_F(MainLoopTest, ReadObject) {
   ASSERT_EQ(1u, callback_count);
 }
 
+TEST_F(MainLoopTest, NoSpuriousReads) {
+  // Write one byte into the socket.
+  char X = 'X';
+  size_t len = sizeof(X);
+  ASSERT_TRUE(socketpair[0]->Write(&X, len).Success());
+
+  MainLoop loop;
+
+  Status error;
+  auto handle = loop.RegisterReadObject(
+      socketpair[1],
+      [this](MainLoopBase &) {
+        if (callback_count == 0) {
+          // Read the byte back the first time we're called. After that, the
+          // socket is empty, and we should not be called anymore.
+          char X;
+          size_t len = sizeof(X);
+          EXPECT_THAT_ERROR(socketpair[1]->Read(&X, len).ToError(),
+                            llvm::Succeeded());
+          EXPECT_EQ(len, sizeof(X));
+        }
+        ++callback_count;
+      },
+      error);
+  ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
+  // Terminate the loop after one second.
+  std::thread terminate_thread([&loop] {
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+    loop.AddPendingCallback(
+        [](MainLoopBase &loop) { loop.RequestTermination(); });
+  });
+  ASSERT_THAT_ERROR(loop.Run().ToError(), llvm::Succeeded());
+  terminate_thread.join();
+
+  // Make sure the callback was called only once.
+  ASSERT_EQ(1u, callback_count);
+}
+
 TEST_F(MainLoopTest, TerminatesImmediately) {
   char X = 'X';
   size_t len = sizeof(X);



More information about the lldb-commits mailing list