mgorny updated this revision to Diff 452714.
mgorny added a comment.

Rebase on top of D131159 <https://reviews.llvm.org/D131159> and partially 
implement the Linux counterpart.

Note that I have only covered `sys/event.h` for now and that I haven't tested 
the updated Windows code.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D131160/new/

https://reviews.llvm.org/D131160

Files:
  lldb/include/lldb/Host/MainLoopBase.h
  lldb/include/lldb/Host/posix/MainLoopPosix.h
  lldb/include/lldb/Host/windows/MainLoopWindows.h
  lldb/source/Host/common/MainLoopBase.cpp
  lldb/source/Host/posix/MainLoopPosix.cpp
  lldb/source/Host/windows/MainLoopWindows.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/windows/MainLoopWindows.cpp
===================================================================
--- lldb/source/Host/windows/MainLoopWindows.cpp
+++ lldb/source/Host/windows/MainLoopWindows.cpp
@@ -21,9 +21,19 @@
 using namespace lldb;
 using namespace lldb_private;
 
+MainLoopWindows::MainLoopWindows() {
+  m_event_event = WSACreateEvent();
+  assert(m_event_event != WSA_INVALID_EVENT);
+}
+
+MainLoopWindows::~MainLoopWindows() {
+  BOOL result = WSACloseEvent(m_event_event);
+  assert(result == TRUE);
+}
+
 llvm::Expected<size_t> MainLoopWindows::Poll() {
-  std::vector<WSAEVENT> read_events;
-  read_events.reserve(m_read_fds.size());
+  std::vector<WSAEVENT> events;
+  events.reserve(m_read_fds.size() + 1);
   for (auto &fd : m_read_fds) {
     WSAEVENT event = WSACreateEvent();
     assert(event != WSA_INVALID_EVENT);
@@ -32,24 +42,25 @@
         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 : 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())
     return result - WSA_WAIT_EVENT_0;
 
   return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -73,16 +84,29 @@
   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 && (!m_read_fds.empty() || !m_events.empty())) {
 
     llvm::Expected<size_t> signaled_event = Poll();
     if (!signaled_event)
       return Status(signaled_event.takeError());
 
-    auto &fd_info = *std::next(m_read_fds.begin(), *signaled_event);
+    if (*signaled_event < m_read_fds.size()) {
+      auto &fd_info = *std::next(m_read_fds.begin(), *signaled_event);
+      ProcessReadObject(fd_info.first);
+    } else {
+      assert(*signaled_event == m_read_fds.size());
+      // Must be called before events are processed.
+      WSAResetEvent(m_event_event);
+      ProcessEvents();
+    }
 
-    ProcessReadObject(fd_info.first);
     ProcessPendingCallbacks();
   }
   return Status();
 }
+
+void MainLoopWindows::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);
+  WSASetEvent(m_event_event);
+}
Index: lldb/source/Host/posix/MainLoopPosix.cpp
===================================================================
--- lldb/source/Host/posix/MainLoopPosix.cpp
+++ lldb/source/Host/posix/MainLoopPosix.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Host/posix/MainLoopPosix.h"
+
 #include "lldb/Host/Config.h"
 #include "lldb/Host/PosixApi.h"
 #include "lldb/Utility/Status.h"
@@ -70,14 +71,15 @@
 
 #if HAVE_SYS_EVENT_H
 MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) {
-  in_events.reserve(loop.m_read_fds.size());
+  in_events.reserve(loop.m_read_fds.size() + 1);
 }
 
 Status MainLoopPosix::RunImpl::Poll() {
-  in_events.resize(loop.m_read_fds.size());
+  in_events.resize(loop.m_read_fds.size() + 1);
   unsigned i = 0;
   for (auto &fd : loop.m_read_fds)
     EV_SET(&in_events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
+  EV_SET(&in_events[i++], m_event_pipe.GetReadFileDescriptor());
 
   num_events = kevent(loop.m_kqueue, in_events.data(), in_events.size(),
                       out_events, llvm::array_lengthof(out_events), nullptr);
@@ -94,13 +96,23 @@
 }
 
 void MainLoopPosix::RunImpl::ProcessEvents() {
+  const int event_pipe_fd = m_event_pipe.GetReadFileDescriptor();
+
   assert(num_events >= 0);
   for (int i = 0; i < num_events; ++i) {
     if (loop.m_terminate_request)
       return;
     switch (out_events[i].filter) {
     case EVFILT_READ:
-      loop.ProcessReadObject(out_events[i].ident);
+      if (out_events[i].ident == event_pipe_fd) {
+        char c;
+        ssize_t bytes_read =
+            llvm::sys::RetryAfterSignal(-1, ::read, event_pipe_fd, &c, 1);
+        assert(bytes_read == 1);
+        UNUSED_IF_ASSERT_DISABLED(bytes_read);
+        loop.ProcessEvents();
+      } else
+        loop.ProcessReadObject(out_events[i].ident);
       break;
     case EVFILT_SIGNAL:
       loop.ProcessSignal(out_events[i].ident);
@@ -113,7 +125,7 @@
 #else
 MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) {
 #ifndef __ANDROID__
-  read_fds.reserve(loop.m_read_fds.size());
+  read_fds.reserve(loop.m_read_fds.size() + 1);
 #endif
 }
 
@@ -138,6 +150,7 @@
 
   FD_ZERO(&read_fd_set);
   int nfds = 0;
+  // TODO: "event"
   for (const auto &fd : loop.m_read_fds) {
     FD_SET(fd.first, &read_fd_set);
     nfds = std::max(nfds, fd.first + 1);
@@ -167,6 +180,7 @@
 
   sigset_t sigmask = get_sigmask();
 
+  // TODO: "event"
   for (const auto &fd : loop.m_read_fds) {
     struct pollfd pfd;
     pfd.fd = fd.first;
@@ -222,6 +236,8 @@
 #endif
 
 MainLoopPosix::MainLoopPosix() {
+  Status error = m_event_pipe.CreateNew(/*child_process_inherit=*/ false);
+  assert(error.Success());
 #if HAVE_SYS_EVENT_H
   m_kqueue = kqueue();
   assert(m_kqueue >= 0);
@@ -232,6 +248,7 @@
 #if HAVE_SYS_EVENT_H
   close(m_kqueue);
 #endif
+  m_event_pipe.Close();
   assert(m_signals.size() == 0);
 }
 
@@ -321,7 +338,8 @@
   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())
@@ -345,3 +363,14 @@
       x(*this); // Do the work
   }
 }
+
+void MainLoopPosix::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);
+  char c = '.';
+  size_t bytes_written;
+  Status error = m_event_pipe.Write(&c, 1, bytes_written);
+  assert(error.Success());
+  UNUSED_IF_ASSERT_DISABLED(error);
+  assert(bytes_written == 1);
+}
Index: lldb/source/Host/common/MainLoopBase.cpp
===================================================================
--- lldb/source/Host/common/MainLoopBase.cpp
+++ lldb/source/Host/common/MainLoopBase.cpp
@@ -30,18 +30,38 @@
   return CreateReadHandle(object_sp);
 }
 
+MainLoopBase::EventHandleUP
+MainLoopBase::RegisterEvent(const Callback &callback) {
+  return CreateEventHandle(callback);
+}
+
 void MainLoopBase::UnregisterReadObject(IOObject::WaitableHandle handle) {
   bool erased = m_read_fds.erase(handle);
   UNUSED_IF_ASSERT_DISABLED(erased);
   assert(erased);
 }
 
+void MainLoopBase::UnregisterEvent(std::list<EventInfo>::iterator info_it) {
+  m_events.erase(info_it);
+}
+
 void MainLoopBase::ProcessReadObject(IOObject::WaitableHandle handle) {
   auto it = m_read_fds.find(handle);
   if (it != m_read_fds.end())
     it->second(*this); // Do the work
 }
 
+void MainLoopBase::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
+}
+
 void MainLoopBase::ProcessPendingCallbacks() {
   for (const Callback &callback : m_pending_callbacks)
     callback(*this);
Index: lldb/include/lldb/Host/windows/MainLoopWindows.h
===================================================================
--- lldb/include/lldb/Host/windows/MainLoopWindows.h
+++ lldb/include/lldb/Host/windows/MainLoopWindows.h
@@ -22,14 +22,20 @@
 // descriptors are not supported.
 class MainLoopWindows : public MainLoopBase {
 public:
+  MainLoopWindows();
+  ~MainLoopWindows() override;
+
   ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp,
                                   const Callback &callback,
                                   Status &error) override;
 
   Status Run() override;
 
+  void NotifyEvent(std::list<EventInfo>::iterator info_it) override;
+
 private:
   llvm::Expected<size_t> Poll();
+  void *m_event_event;
 };
 
 } // namespace lldb_private
Index: lldb/include/lldb/Host/posix/MainLoopPosix.h
===================================================================
--- lldb/include/lldb/Host/posix/MainLoopPosix.h
+++ lldb/include/lldb/Host/posix/MainLoopPosix.h
@@ -11,6 +11,7 @@
 
 #include "lldb/Host/Config.h"
 #include "lldb/Host/MainLoopBase.h"
+#include "lldb/Host/Pipe.h"
 #include "llvm/ADT/DenseMap.h"
 #include <csignal>
 #include <list>
@@ -44,6 +45,8 @@
 
   Status Run() override;
 
+  void NotifyEvent(std::list<EventInfo>::iterator info_it) override;
+
 protected:
   void UnregisterSignal(int signo, std::list<Callback>::iterator callback_it);
 
@@ -76,6 +79,7 @@
   class RunImpl;
 
   llvm::DenseMap<int, SignalInfo> m_signals;
+  Pipe m_event_pipe;
 #if HAVE_SYS_EVENT_H
   int m_kqueue;
 #endif
Index: lldb/include/lldb/Host/MainLoopBase.h
===================================================================
--- lldb/include/lldb/Host/MainLoopBase.h
+++ lldb/include/lldb/Host/MainLoopBase.h
@@ -13,7 +13,10 @@
 #include "lldb/Utility/Status.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/Support/ErrorHandling.h"
+
+#include <atomic>
 #include <functional>
+#include <list>
 
 namespace lldb_private {
 
@@ -35,12 +38,14 @@
 class MainLoopBase {
 private:
   class ReadHandle;
+  class EventHandle;
 
 public:
   MainLoopBase() : m_terminate_request(false) {}
   virtual ~MainLoopBase() { assert(m_read_fds.size() == 0); }
 
   typedef std::unique_ptr<ReadHandle> ReadHandleUP;
+  typedef std::unique_ptr<EventHandle> EventHandleUP;
 
   typedef std::function<void(MainLoopBase &)> Callback;
 
@@ -48,6 +53,8 @@
                                           const Callback &callback,
                                           Status &error);
 
+  virtual 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.
@@ -64,16 +71,34 @@
   virtual void RequestTermination() { m_terminate_request = true; }
 
 protected:
+  struct EventInfo {
+    EventInfo(Callback callback)
+        : notified(false), callback(std::move(callback)) {}
+    std::atomic<bool> notified;
+    Callback callback;
+  };
+
   ReadHandleUP CreateReadHandle(const lldb::IOObjectSP &object_sp) {
     return ReadHandleUP(new ReadHandle(*this, object_sp->GetWaitableHandle()));
   }
 
   virtual void UnregisterReadObject(IOObject::WaitableHandle handle);
 
+  EventHandleUP CreateEventHandle(const Callback &callback) {
+    return EventHandleUP(
+        new EventHandle(*this, m_events.emplace(m_events.end(), callback)));
+  }
+
+  virtual void UnregisterEvent(std::list<EventInfo>::iterator info_it);
+
   void ProcessReadObject(IOObject::WaitableHandle handle);
+  void ProcessEvents();
   void ProcessPendingCallbacks();
 
+  virtual void NotifyEvent(std::list<EventInfo>::iterator info_it) = 0;
+
   llvm::DenseMap<IOObject::WaitableHandle, Callback> m_read_fds;
+  std::list<EventInfo> m_events;
   std::vector<Callback> m_pending_callbacks;
   bool m_terminate_request : 1;
 
@@ -94,6 +119,24 @@
     const ReadHandle &operator=(const ReadHandle &) = delete;
   };
 
+  class EventHandle {
+  public:
+    ~EventHandle() { m_mainloop.UnregisterEvent(m_info_it); }
+
+    void Notify() { m_mainloop.NotifyEvent(m_info_it); }
+
+  private:
+    EventHandle(MainLoopBase &mainloop, std::list<EventInfo>::iterator info_it)
+        : m_mainloop(mainloop), m_info_it(info_it) {}
+
+    MainLoopBase &m_mainloop;
+    std::list<EventInfo>::iterator m_info_it;
+
+    friend class MainLoopBase;
+    EventHandle(const EventHandle &) = delete;
+    const EventHandle &operator=(const EventHandle &) = delete;
+  };
+
   MainLoopBase(const MainLoopBase &) = delete;
   const MainLoopBase &operator=(const MainLoopBase &) = delete;
 };
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to