labath created this revision.
labath added a reviewer: mgorny.
Herald added a project: All.
labath requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D131160

Files:
  lldb/include/lldb/Host/MainLoop.h
  lldb/source/Host/common/MainLoop.cpp
  lldb/unittests/Host/MainLoopTest.cpp

Index: lldb/unittests/Host/MainLoopTest.cpp
===================================================================
--- lldb/unittests/Host/MainLoopTest.cpp
+++ lldb/unittests/Host/MainLoopTest.cpp
@@ -148,6 +148,18 @@
   ASSERT_EQ(3u, callback_count);
 }
 
+TEST_F(MainLoopTest, Event) {
+  MainLoop loop;
+  bool event_called = false;
+  auto handle = loop.RegisterEvent([&](MainLoopBase &loop) {
+    event_called = true;
+    loop.RequestTermination();
+  });
+  handle->Notify();
+  ASSERT_THAT_ERROR(loop.Run().ToError(), llvm::Succeeded());
+  ASSERT_TRUE(event_called);
+}
+
 #ifdef LLVM_ON_UNIX
 TEST_F(MainLoopTest, DetectsEOF) {
 
Index: lldb/source/Host/common/MainLoop.cpp
===================================================================
--- lldb/source/Host/common/MainLoop.cpp
+++ lldb/source/Host/common/MainLoop.cpp
@@ -91,8 +91,8 @@
 }
 
 Status MainLoop::RunImpl::Poll() {
-  std::vector<WSAEVENT> read_events;
-  read_events.reserve(loop.m_read_fds.size());
+  std::vector<WSAEVENT> events;
+  events.reserve(loop.m_read_fds.size() + 1);
   for(auto &fd : loop.m_read_fds) {
     WSAEVENT event = WSACreateEvent();
     assert(event != WSA_INVALID_EVENT);
@@ -100,23 +100,25 @@
     int result = WSAEventSelect(fd.first, event, FD_READ | FD_ACCEPT | FD_CLOSE);
     assert(result == 0);
 
-    read_events.push_back(event);
+    events.push_back(event);
   }
+  events.push_back(loop.m_event_event);
 
-  DWORD result = WSAWaitForMultipleEvents(read_events.size(),
-      read_events.data(), FALSE, WSA_INFINITE, FALSE);
+  DWORD result = WSAWaitForMultipleEvents(events.size(),
+      events.data(), FALSE, WSA_INFINITE, FALSE);
 
   for(auto &fd : loop.m_read_fds) {
     int result = WSAEventSelect(fd.first, WSA_INVALID_EVENT, 0);
     assert(result == 0);
   }
 
-  for (auto &event: read_events) {
+  events.pop_back();
+  for (auto &event: events) {
     BOOL result = WSACloseEvent(event);
     assert(result == TRUE);
   }
 
-  if (result >= WSA_WAIT_EVENT_0 && result < WSA_WAIT_EVENT_0 + read_events.size()) {
+  if (result >= WSA_WAIT_EVENT_0 && result <= WSA_WAIT_EVENT_0 + events.size()) {
     signaled_event = result - WSA_WAIT_EVENT_0;
     return Status();
   }
@@ -125,9 +127,14 @@
 
 void MainLoop::RunImpl::ProcessEvents() {
   assert(signaled_event);
-  auto &fd_info = *std::next(loop.m_read_fds.begin(), *signaled_event);
-
-  loop.ProcessReadObject(fd_info.first);
+  if (*signaled_event < loop.m_read_fds.size()) {
+    auto &fd_info = *std::next(loop.m_read_fds.begin(), *signaled_event);
+    loop.ProcessReadObject(fd_info.first);
+  } else {
+    // Must be called before events are processed.
+    WSAResetEvent(loop.m_event_event);
+    loop.ProcessEvents();
+  }
 }
 #else
 class MainLoop::RunImpl {
@@ -317,11 +324,27 @@
 #endif
 #endif
 
+void MainLoop::NotifyEvent(std::list<EventInfo>::iterator info_it) {
+  // This must be set before we notify the event.
+  info_it->notified.store(true, std::memory_order_release);
+#ifdef _WIN32
+  WSASetEvent(m_event_event);
+#else
+  ...
+#endif
+}
+
 MainLoop::MainLoop() : m_terminate_request(false) {
 #if HAVE_SYS_EVENT_H
   m_kqueue = kqueue();
   assert(m_kqueue >= 0);
 #endif
+#ifdef _WIN32
+  m_event_event = WSACreateEvent();
+  assert(m_event_event != WSA_INVALID_EVENT);
+#else
+  ...
+#endif
 }
 MainLoop::~MainLoop() {
 #if HAVE_SYS_EVENT_H
@@ -409,6 +432,10 @@
 #endif
 }
 
+MainLoop::EventHandleUP MainLoop::RegisterEvent(const Callback &callback) {
+  return EventHandleUP(new EventHandle(*this, m_events.emplace(m_events.end(), callback)));
+}
+
 void MainLoop::AddPendingCallback(const Callback &callback) {
   m_pending_callbacks.push_back(callback);
 }
@@ -419,6 +446,10 @@
   assert(erased);
 }
 
+void MainLoop::UnregisterEvent(std::list<EventInfo>::iterator info_it) {
+  m_events.erase(info_it);
+}
+
 void MainLoop::UnregisterSignal(int signo,
                                 std::list<Callback>::iterator callback_it) {
 #if SIGNAL_POLLING_UNSUPPORTED
@@ -460,7 +491,7 @@
   RunImpl impl(*this);
 
   // run until termination or until we run out of things to listen to
-  while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) {
+  while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty() || !m_events.empty())) {
 
     error = impl.Poll();
     if (error.Fail())
@@ -492,3 +523,14 @@
   if (it != m_read_fds.end())
     it->second(*this); // Do the work
 }
+
+void MainLoop::ProcessEvents() {
+  // Create a copy as some events may become unregistered by the callbacks.
+  llvm::SmallVector<Callback, 4> callbacks_to_run;
+  for (auto &info : m_events) {
+    if (info.notified.exchange(false, std::memory_order_acq_rel) == true)
+      callbacks_to_run.push_back(info.callback);
+  }
+  for (auto &cb : callbacks_to_run)
+    cb(*this); // Do the work
+}
Index: lldb/include/lldb/Host/MainLoop.h
===================================================================
--- lldb/include/lldb/Host/MainLoop.h
+++ lldb/include/lldb/Host/MainLoop.h
@@ -39,9 +39,12 @@
 class MainLoop : public MainLoopBase {
 private:
   class SignalHandle;
+  class EventHandle;
+  struct EventInfo;
 
 public:
   typedef std::unique_ptr<SignalHandle> SignalHandleUP;
+  typedef std::unique_ptr<EventHandle> EventHandleUP;
 
   MainLoop();
   ~MainLoop() override;
@@ -60,6 +63,8 @@
   SignalHandleUP RegisterSignal(int signo, const Callback &callback,
                                 Status &error);
 
+  EventHandleUP RegisterEvent(const Callback &callback);
+
   // Add a pending callback that will be executed once after all the pending
   // events are processed. The callback will be executed even if termination
   // was requested.
@@ -77,9 +82,14 @@
 
   void UnregisterSignal(int signo, std::list<Callback>::iterator callback_it);
 
+  void UnregisterEvent(std::list<EventInfo>::iterator info_it);
+
 private:
   void ProcessReadObject(IOObject::WaitableHandle handle);
   void ProcessSignal(int signo);
+  void ProcessEvents();
+
+  void NotifyEvent(std::list<EventInfo>::iterator info_it);
 
   class SignalHandle {
   public:
@@ -99,6 +109,19 @@
     const SignalHandle &operator=(const SignalHandle &) = delete;
   };
 
+  class EventHandle {
+  public:
+    EventHandle(MainLoop &mainloop, std::list<EventInfo>::iterator info_it)
+        : m_mainloop(mainloop), m_info_it(info_it) {}
+    ~EventHandle() { m_mainloop.UnregisterEvent(m_info_it); }
+
+    void Notify() { m_mainloop.NotifyEvent(m_info_it); }
+
+  private:
+    MainLoop &m_mainloop;
+    std::list<EventInfo>::iterator m_info_it;
+  };
+
   struct SignalInfo {
     std::list<Callback> callbacks;
 #ifndef SIGNAL_POLLING_UNSUPPORTED
@@ -106,13 +129,25 @@
 #endif
     bool was_blocked : 1;
   };
+  struct EventInfo {
+    EventInfo(Callback callback)
+        : notified(false), callback(std::move(callback)) {}
+    std::atomic<bool> notified;
+    Callback callback;
+  };
   class RunImpl;
 
   llvm::DenseMap<IOObject::WaitableHandle, Callback> m_read_fds;
   llvm::DenseMap<int, SignalInfo> m_signals;
+  std::list<EventInfo> m_events;
   std::vector<Callback> m_pending_callbacks;
 #if HAVE_SYS_EVENT_H
   int m_kqueue;
+#endif
+#ifdef _WIN32
+  void *m_event_event;
+#else
+  Pipe m_event_pipe;
 #endif
   bool m_terminate_request : 1;
 };
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to