This revision was automatically updated to reflect the committed changes.
Closed by commit rGc74c17f37aa9: [lldb] Use WSAEventSelect for MainLoop polling 
on windows (authored by labath).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D131159

Files:
  lldb/include/lldb/Host/MainLoop.h
  lldb/include/lldb/Host/MainLoopBase.h
  lldb/include/lldb/Host/posix/MainLoopPosix.h
  lldb/include/lldb/Host/windows/MainLoopWindows.h
  lldb/source/Host/CMakeLists.txt
  lldb/source/Host/common/MainLoop.cpp
  lldb/source/Host/common/MainLoopBase.cpp
  lldb/source/Host/posix/MainLoopPosix.cpp
  lldb/source/Host/windows/MainLoopWindows.cpp

Index: lldb/source/Host/windows/MainLoopWindows.cpp
===================================================================
--- /dev/null
+++ lldb/source/Host/windows/MainLoopWindows.cpp
@@ -0,0 +1,115 @@
+//===-- MainLoopWindows.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/windows/MainLoopWindows.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Utility/Status.h"
+#include "llvm/Config/llvm-config.h"
+#include <algorithm>
+#include <cassert>
+#include <cerrno>
+#include <csignal>
+#include <ctime>
+#include <vector>
+#include <winsock2.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+llvm::Expected<size_t> MainLoopWindows::Poll() {
+  std::vector<WSAEVENT> read_events;
+  read_events.reserve(m_read_fds.size());
+  for (auto &[fd, info] : m_read_fds) {
+    int result = WSAEventSelect(fd, info.event, FD_READ | FD_ACCEPT | FD_CLOSE);
+    assert(result == 0);
+
+    read_events.push_back(info.event);
+  }
+
+  DWORD result = WSAWaitForMultipleEvents(
+      read_events.size(), read_events.data(), FALSE, WSA_INFINITE, FALSE);
+
+  for (auto &fd : m_read_fds) {
+    int result = WSAEventSelect(fd.first, WSA_INVALID_EVENT, 0);
+    assert(result == 0);
+  }
+
+  if (result >= WSA_WAIT_EVENT_0 &&
+      result < WSA_WAIT_EVENT_0 + read_events.size())
+    return result - WSA_WAIT_EVENT_0;
+
+  return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                 "WSAWaitForMultipleEvents failed");
+}
+
+MainLoopWindows::ReadHandleUP
+MainLoopWindows::RegisterReadObject(const IOObjectSP &object_sp,
+                                    const Callback &callback, Status &error) {
+  if (!object_sp || !object_sp->IsValid()) {
+    error.SetErrorString("IO object is not valid.");
+    return nullptr;
+  }
+  if (object_sp->GetFdType() != IOObject::eFDTypeSocket) {
+    error.SetErrorString(
+        "MainLoopWindows: non-socket types unsupported on Windows");
+    return nullptr;
+  }
+
+  WSAEVENT event = WSACreateEvent();
+  if (event == WSA_INVALID_EVENT) {
+    error.SetErrorStringWithFormat("Cannot create monitoring event.");
+    return nullptr;
+  }
+
+  const bool inserted =
+      m_read_fds
+          .try_emplace(object_sp->GetWaitableHandle(), FdInfo{event, callback})
+          .second;
+  if (!inserted) {
+    WSACloseEvent(event);
+    error.SetErrorStringWithFormat("File descriptor %d already monitored.",
+                                   object_sp->GetWaitableHandle());
+    return nullptr;
+  }
+
+  return CreateReadHandle(object_sp);
+}
+
+void MainLoopWindows::UnregisterReadObject(IOObject::WaitableHandle handle) {
+  auto it = m_read_fds.find(handle);
+  assert(it != m_read_fds.end());
+  BOOL result = WSACloseEvent(it->second.event);
+  assert(result == TRUE);
+  m_read_fds.erase(it);
+}
+
+void MainLoopWindows::ProcessReadObject(IOObject::WaitableHandle handle) {
+  auto it = m_read_fds.find(handle);
+  if (it != m_read_fds.end())
+    it->second.callback(*this); // Do the work
+}
+
+Status MainLoopWindows::Run() {
+  m_terminate_request = false;
+
+  Status error;
+
+  // run until termination or until we run out of things to listen to
+  while (!m_terminate_request && !m_read_fds.empty()) {
+
+    llvm::Expected<size_t> signaled_event = Poll();
+    if (!signaled_event)
+      return Status(signaled_event.takeError());
+
+    auto &KV = *std::next(m_read_fds.begin(), *signaled_event);
+
+    ProcessReadObject(KV.first);
+    ProcessPendingCallbacks();
+  }
+  return Status();
+}
Index: lldb/source/Host/posix/MainLoopPosix.cpp
===================================================================
--- lldb/source/Host/posix/MainLoopPosix.cpp
+++ lldb/source/Host/posix/MainLoopPosix.cpp
@@ -1,4 +1,4 @@
-//===-- MainLoop.cpp ------------------------------------------------------===//
+//===-- MainLoopPosix.cpp -------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,12 +6,11 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/Config/llvm-config.h"
+#include "lldb/Host/posix/MainLoopPosix.h"
 #include "lldb/Host/Config.h"
-
-#include "lldb/Host/MainLoop.h"
 #include "lldb/Host/PosixApi.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/Config/llvm-config.h"
 #include <algorithm>
 #include <cassert>
 #include <cerrno>
@@ -26,59 +25,32 @@
 
 #if HAVE_SYS_EVENT_H
 #include <sys/event.h>
-#elif defined(_WIN32)
-#include <winsock2.h>
 #elif defined(__ANDROID__)
 #include <sys/syscall.h>
 #else
 #include <poll.h>
 #endif
 
-#ifdef _WIN32
-#define POLL WSAPoll
-#else
-#define POLL poll
-#endif
-
-#if SIGNAL_POLLING_UNSUPPORTED
-#ifdef _WIN32
-typedef int sigset_t;
-typedef int siginfo_t;
-#endif
-
-int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout_ts,
-          const sigset_t *) {
-  int timeout =
-      (timeout_ts == nullptr)
-          ? -1
-          : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000);
-  return POLL(fds, nfds, timeout);
-}
-
-#endif
-
 using namespace lldb;
 using namespace lldb_private;
 
 static sig_atomic_t g_signal_flags[NSIG];
 
-#ifndef SIGNAL_POLLING_UNSUPPORTED
 static void SignalHandler(int signo, siginfo_t *info, void *) {
   assert(signo < NSIG);
   g_signal_flags[signo] = 1;
 }
-#endif
 
-class MainLoop::RunImpl {
+class MainLoopPosix::RunImpl {
 public:
-  RunImpl(MainLoop &loop);
+  RunImpl(MainLoopPosix &loop);
   ~RunImpl() = default;
 
   Status Poll();
   void ProcessEvents();
 
 private:
-  MainLoop &loop;
+  MainLoopPosix &loop;
 
 #if HAVE_SYS_EVENT_H
   std::vector<struct kevent> in_events;
@@ -97,11 +69,11 @@
 };
 
 #if HAVE_SYS_EVENT_H
-MainLoop::RunImpl::RunImpl(MainLoop &loop) : loop(loop) {
+MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) {
   in_events.reserve(loop.m_read_fds.size());
 }
 
-Status MainLoop::RunImpl::Poll() {
+Status MainLoopPosix::RunImpl::Poll() {
   in_events.resize(loop.m_read_fds.size());
   unsigned i = 0;
   for (auto &fd : loop.m_read_fds)
@@ -121,7 +93,7 @@
   return Status();
 }
 
-void MainLoop::RunImpl::ProcessEvents() {
+void MainLoopPosix::RunImpl::ProcessEvents() {
   assert(num_events >= 0);
   for (int i = 0; i < num_events; ++i) {
     if (loop.m_terminate_request)
@@ -139,31 +111,25 @@
   }
 }
 #else
-MainLoop::RunImpl::RunImpl(MainLoop &loop) : loop(loop) {
+MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) {
 #ifndef __ANDROID__
   read_fds.reserve(loop.m_read_fds.size());
 #endif
 }
 
-sigset_t MainLoop::RunImpl::get_sigmask() {
+sigset_t MainLoopPosix::RunImpl::get_sigmask() {
   sigset_t sigmask;
-#if defined(_WIN32)
-  sigmask = 0;
-#elif SIGNAL_POLLING_UNSUPPORTED
-  sigemptyset(&sigmask);
-#else
   int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask);
   assert(ret == 0);
-  (void) ret;
+  (void)ret;
 
   for (const auto &sig : loop.m_signals)
     sigdelset(&sigmask, sig.first);
-#endif
   return sigmask;
 }
 
 #ifdef __ANDROID__
-Status MainLoop::RunImpl::Poll() {
+Status MainLoopPosix::RunImpl::Poll() {
   // ppoll(2) is not supported on older all android versions. Also, older
   // versions android (API <= 19) implemented pselect in a non-atomic way, as a
   // combination of pthread_sigmask and select. This is not sufficient for us,
@@ -196,7 +162,7 @@
   return Status();
 }
 #else
-Status MainLoop::RunImpl::Poll() {
+Status MainLoopPosix::RunImpl::Poll() {
   read_fds.clear();
 
   sigset_t sigmask = get_sigmask();
@@ -217,7 +183,7 @@
 }
 #endif
 
-void MainLoop::RunImpl::ProcessEvents() {
+void MainLoopPosix::RunImpl::ProcessEvents() {
 #ifdef __ANDROID__
   // Collect first all readable file descriptors into a separate vector and
   // then iterate over it to invoke callbacks. Iterating directly over
@@ -255,29 +221,24 @@
 }
 #endif
 
-MainLoop::MainLoop() : m_terminate_request(false) {
+MainLoopPosix::MainLoopPosix() {
 #if HAVE_SYS_EVENT_H
   m_kqueue = kqueue();
   assert(m_kqueue >= 0);
 #endif
 }
-MainLoop::~MainLoop() {
+
+MainLoopPosix::~MainLoopPosix() {
 #if HAVE_SYS_EVENT_H
   close(m_kqueue);
 #endif
-  assert(m_read_fds.size() == 0);
+  assert(m_read_fds.size() == 0); 
   assert(m_signals.size() == 0);
 }
 
-MainLoop::ReadHandleUP MainLoop::RegisterReadObject(const IOObjectSP &object_sp,
-                                                    const Callback &callback,
-                                                    Status &error) {
-#ifdef _WIN32
-  if (object_sp->GetFdType() != IOObject:: eFDTypeSocket) {
-    error.SetErrorString("MainLoop: non-socket types unsupported on Windows");
-    return nullptr;
-  }
-#endif
+MainLoopPosix::ReadHandleUP
+MainLoopPosix::RegisterReadObject(const IOObjectSP &object_sp,
+                                 const Callback &callback, Status &error) {
   if (!object_sp || !object_sp->IsValid()) {
     error.SetErrorString("IO object is not valid.");
     return nullptr;
@@ -296,12 +257,9 @@
 
 // We shall block the signal, then install the signal handler. The signal will
 // be unblocked in the Run() function to check for signal delivery.
-MainLoop::SignalHandleUP
-MainLoop::RegisterSignal(int signo, const Callback &callback, Status &error) {
-#ifdef SIGNAL_POLLING_UNSUPPORTED
-  error.SetErrorString("Signal polling is not supported on this platform.");
-  return nullptr;
-#else
+MainLoopPosix::SignalHandleUP
+MainLoopPosix::RegisterSignal(int signo, const Callback &callback,
+                              Status &error) {
   auto signal_it = m_signals.find(signo);
   if (signal_it != m_signals.end()) {
     auto callback_it = signal_it->second.callbacks.insert(
@@ -344,24 +302,16 @@
 
   return SignalHandleUP(new SignalHandle(
       *this, signo, insert_ret.first->second.callbacks.begin()));
-#endif
 }
 
-void MainLoop::AddPendingCallback(const Callback &callback) {
-  m_pending_callbacks.push_back(callback);
-}
-
-void MainLoop::UnregisterReadObject(IOObject::WaitableHandle handle) {
+void MainLoopPosix::UnregisterReadObject(IOObject::WaitableHandle handle) {
   bool erased = m_read_fds.erase(handle);
   UNUSED_IF_ASSERT_DISABLED(erased);
   assert(erased);
 }
 
-void MainLoop::UnregisterSignal(int signo,
-                                std::list<Callback>::iterator callback_it) {
-#if SIGNAL_POLLING_UNSUPPORTED
-  Status("Signal polling is not supported on this platform.");
-#else
+void MainLoopPosix::UnregisterSignal(
+    int signo, std::list<Callback>::iterator callback_it) {
   auto it = m_signals.find(signo);
   assert(it != m_signals.end());
 
@@ -388,10 +338,9 @@
 #endif
 
   m_signals.erase(it);
-#endif
 }
 
-Status MainLoop::Run() {
+Status MainLoopPosix::Run() {
   m_terminate_request = false;
 
   Status error;
@@ -406,14 +355,18 @@
 
     impl.ProcessEvents();
 
-    for (const Callback &callback : m_pending_callbacks)
-      callback(*this);
-    m_pending_callbacks.clear();
+    ProcessPendingCallbacks();
   }
   return Status();
 }
 
-void MainLoop::ProcessSignal(int signo) {
+void MainLoopPosix::ProcessReadObject(IOObject::WaitableHandle handle) {
+  auto it = m_read_fds.find(handle);
+  if (it != m_read_fds.end())
+    it->second(*this); // Do the work
+}
+
+void MainLoopPosix::ProcessSignal(int signo) {
   auto it = m_signals.find(signo);
   if (it != m_signals.end()) {
     // The callback may actually register/unregister signal handlers,
@@ -424,9 +377,3 @@
       x(*this); // Do the work
   }
 }
-
-void MainLoop::ProcessReadObject(IOObject::WaitableHandle handle) {
-  auto it = m_read_fds.find(handle);
-  if (it != m_read_fds.end())
-    it->second(*this); // Do the work
-}
Index: lldb/source/Host/common/MainLoopBase.cpp
===================================================================
--- /dev/null
+++ lldb/source/Host/common/MainLoopBase.cpp
@@ -0,0 +1,18 @@
+//===-- MainLoopBase.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/MainLoopBase.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void MainLoopBase::ProcessPendingCallbacks() {
+  for (const Callback &callback : m_pending_callbacks)
+    callback(*this);
+  m_pending_callbacks.clear();
+}
Index: lldb/source/Host/CMakeLists.txt
===================================================================
--- lldb/source/Host/CMakeLists.txt
+++ lldb/source/Host/CMakeLists.txt
@@ -24,7 +24,7 @@
   common/HostThread.cpp
   common/LockFileBase.cpp
   common/LZMA.cpp
-  common/MainLoop.cpp
+  common/MainLoopBase.cpp
   common/MonitoringProcessLauncher.cpp
   common/NativeProcessProtocol.cpp
   common/NativeRegisterContext.cpp
@@ -63,6 +63,7 @@
     windows/HostProcessWindows.cpp
     windows/HostThreadWindows.cpp
     windows/LockFileWindows.cpp
+    windows/MainLoopWindows.cpp
     windows/PipeWindows.cpp
     windows/ProcessLauncherWindows.cpp
     windows/ProcessRunLock.cpp
@@ -75,6 +76,7 @@
     posix/HostProcessPosix.cpp
     posix/HostThreadPosix.cpp
     posix/LockFilePosix.cpp
+    posix/MainLoopPosix.cpp
     posix/PipePosix.cpp
     posix/ProcessLauncherPosixFork.cpp
     )
Index: lldb/include/lldb/Host/windows/MainLoopWindows.h
===================================================================
--- /dev/null
+++ lldb/include/lldb/Host/windows/MainLoopWindows.h
@@ -0,0 +1,49 @@
+//===-- MainLoopWindows.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_HOST_WINDOWS_MAINLOOPWINDOWS_H
+#define LLDB_HOST_WINDOWS_MAINLOOPWINDOWS_H
+
+#include "lldb/Host/Config.h"
+#include "lldb/Host/MainLoopBase.h"
+#include <csignal>
+#include <list>
+#include <vector>
+
+namespace lldb_private {
+
+// Windows-specific implementation of the MainLoopBase class. It can monitor
+// socket descriptors for readability using WSAEventSelect. Non-socket file
+// descriptors are not supported.
+class MainLoopWindows : public MainLoopBase {
+public:
+  ~MainLoopWindows() override { assert(m_read_fds.empty()); }
+
+  ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp,
+                                  const Callback &callback,
+                                  Status &error) override;
+
+  Status Run() override;
+
+protected:
+  void UnregisterReadObject(IOObject::WaitableHandle handle) override;
+
+private:
+  void ProcessReadObject(IOObject::WaitableHandle handle);
+  llvm::Expected<size_t> Poll();
+
+  struct FdInfo {
+    void *event;
+    Callback callback;
+  };
+  llvm::DenseMap<IOObject::WaitableHandle, FdInfo> m_read_fds;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_HOST_WINDOWS_MAINLOOPWINDOWS_H
Index: lldb/include/lldb/Host/posix/MainLoopPosix.h
===================================================================
--- lldb/include/lldb/Host/posix/MainLoopPosix.h
+++ lldb/include/lldb/Host/posix/MainLoopPosix.h
@@ -1,4 +1,4 @@
-//===-- MainLoop.h ----------------------------------------------*- C++ -*-===//
+//===-- MainLoopPosix.h -----------------------------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLDB_HOST_MAINLOOP_H
-#define LLDB_HOST_MAINLOOP_H
+#ifndef LLDB_HOST_POSIX_MAINLOOPPOSIX_H
+#define LLDB_HOST_POSIX_MAINLOOPPOSIX_H
 
 #include "lldb/Host/Config.h"
 #include "lldb/Host/MainLoopBase.h"
@@ -16,35 +16,21 @@
 #include <list>
 #include <vector>
 
-#if !HAVE_PPOLL && !HAVE_SYS_EVENT_H && !defined(__ANDROID__)
-#define SIGNAL_POLLING_UNSUPPORTED 1
-#endif
-
 namespace lldb_private {
 
-// Implementation of the MainLoopBase class. It can monitor file descriptors
-// for readability using ppoll, kqueue, poll or WSAPoll. On Windows it only
-// supports polling sockets, and will not work on generic file handles or
-// pipes. On systems without kqueue or ppoll handling singnals is not
-// supported. In addition to the common base, this class provides the ability
-// to invoke a given handler when a signal is received.
-//
-// Since this class is primarily intended to be used for single-threaded
-// processing, it does not attempt to perform any internal synchronisation and
-// any concurrent accesses must be protected  externally. However, it is
-// perfectly legitimate to have more than one instance of this class running on
-// separate threads, or even a single thread (with some limitations on signal
-// monitoring).
-// TODO: Add locking if this class is to be used in a multi-threaded context.
-class MainLoop : public MainLoopBase {
+// Implementation of the MainLoopBase class. It can monitor file descriptors for
+// readability using ppoll, kqueue, or pselect. In addition to the common base,
+// this class provides the ability to invoke a given handler when a signal is
+// received.
+class MainLoopPosix : public MainLoopBase {
 private:
   class SignalHandle;
 
 public:
   typedef std::unique_ptr<SignalHandle> SignalHandleUP;
 
-  MainLoop();
-  ~MainLoop() override;
+  MainLoopPosix();
+  ~MainLoopPosix() override;
 
   ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp,
                                   const Callback &callback,
@@ -60,21 +46,10 @@
   SignalHandleUP RegisterSignal(int signo, const Callback &callback,
                                 Status &error);
 
-  // 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.
-  void AddPendingCallback(const Callback &callback) override;
-
   Status Run() override;
 
-  // This should only be performed from a callback. Do not attempt to terminate
-  // the processing from another thread.
-  // TODO: Add synchronization if we want to be terminated from another thread.
-  void RequestTermination() override { m_terminate_request = true; }
-
 protected:
   void UnregisterReadObject(IOObject::WaitableHandle handle) override;
-
   void UnregisterSignal(int signo, std::list<Callback>::iterator callback_it);
 
 private:
@@ -86,37 +61,33 @@
     ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo, m_callback_it); }
 
   private:
-    SignalHandle(MainLoop &mainloop, int signo,
+    SignalHandle(MainLoopPosix &mainloop, int signo,
                  std::list<Callback>::iterator callback_it)
         : m_mainloop(mainloop), m_signo(signo), m_callback_it(callback_it) {}
 
-    MainLoop &m_mainloop;
+    MainLoopPosix &m_mainloop;
     int m_signo;
     std::list<Callback>::iterator m_callback_it;
 
-    friend class MainLoop;
+    friend class MainLoopPosix;
     SignalHandle(const SignalHandle &) = delete;
     const SignalHandle &operator=(const SignalHandle &) = delete;
   };
 
   struct SignalInfo {
     std::list<Callback> callbacks;
-#ifndef SIGNAL_POLLING_UNSUPPORTED
     struct sigaction old_action;
-#endif
     bool was_blocked : 1;
   };
   class RunImpl;
 
   llvm::DenseMap<IOObject::WaitableHandle, Callback> m_read_fds;
   llvm::DenseMap<int, SignalInfo> m_signals;
-  std::vector<Callback> m_pending_callbacks;
 #if HAVE_SYS_EVENT_H
   int m_kqueue;
 #endif
-  bool m_terminate_request : 1;
 };
 
 } // namespace lldb_private
 
-#endif // LLDB_HOST_MAINLOOP_H
+#endif // LLDB_HOST_POSIX_MAINLOOPPOSIX_H
Index: lldb/include/lldb/Host/MainLoopBase.h
===================================================================
--- lldb/include/lldb/Host/MainLoopBase.h
+++ lldb/include/lldb/Host/MainLoopBase.h
@@ -11,6 +11,7 @@
 
 #include "lldb/Utility/IOObject.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/Support/ErrorHandling.h"
 #include <functional>
 
@@ -26,14 +27,17 @@
 // of the monitoring. When this handle is destroyed, the callback is
 // deregistered.
 //
-// This class simply defines the interface common for all platforms, actual
-// implementations are platform-specific.
+// Since this class is primarily intended to be used for single-threaded
+// processing, it does not attempt to perform any internal synchronisation and
+// any concurrent accesses must be protected  externally. However, it is
+// perfectly legitimate to have more than one instance of this class running on
+// separate threads, or even a single thread.
 class MainLoopBase {
 private:
   class ReadHandle;
 
 public:
-  MainLoopBase() = default;
+  MainLoopBase() : m_terminate_request(false) {}
   virtual ~MainLoopBase() = default;
 
   typedef std::unique_ptr<ReadHandle> ReadHandleUP;
@@ -42,32 +46,34 @@
 
   virtual ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp,
                                           const Callback &callback,
-                                          Status &error) {
-    llvm_unreachable("Not implemented");
-  }
+                                          Status &error) = 0;
 
   // 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.
   virtual void AddPendingCallback(const Callback &callback) {
-    llvm_unreachable("Not implemented");
+    m_pending_callbacks.push_back(callback);
   }
 
   // Waits for registered events and invoke the proper callbacks. Returns when
   // all callbacks deregister themselves or when someone requests termination.
   virtual Status Run() { llvm_unreachable("Not implemented"); }
 
-  // Requests the exit of the Run() function.
-  virtual void RequestTermination() { llvm_unreachable("Not implemented"); }
+  // This should only be performed from a callback. Do not attempt to terminate
+  // the processing from another thread.
+  virtual void RequestTermination() { m_terminate_request = true; }
 
 protected:
   ReadHandleUP CreateReadHandle(const lldb::IOObjectSP &object_sp) {
     return ReadHandleUP(new ReadHandle(*this, object_sp->GetWaitableHandle()));
   }
 
-  virtual void UnregisterReadObject(IOObject::WaitableHandle handle) {
-    llvm_unreachable("Not implemented");
-  }
+  virtual void UnregisterReadObject(IOObject::WaitableHandle handle) = 0;
+
+  void ProcessPendingCallbacks();
+
+  std::vector<Callback> m_pending_callbacks;
+  bool m_terminate_request : 1;
 
 private:
   class ReadHandle {
Index: lldb/include/lldb/Host/MainLoop.h
===================================================================
--- lldb/include/lldb/Host/MainLoop.h
+++ lldb/include/lldb/Host/MainLoop.h
@@ -9,114 +9,16 @@
 #ifndef LLDB_HOST_MAINLOOP_H
 #define LLDB_HOST_MAINLOOP_H
 
-#include "lldb/Host/Config.h"
-#include "lldb/Host/MainLoopBase.h"
-#include "llvm/ADT/DenseMap.h"
-#include <csignal>
-#include <list>
-#include <vector>
-
-#if !HAVE_PPOLL && !HAVE_SYS_EVENT_H && !defined(__ANDROID__)
-#define SIGNAL_POLLING_UNSUPPORTED 1
-#endif
-
+#ifdef _WIN32
+#include "lldb/Host/windows/MainLoopWindows.h"
 namespace lldb_private {
-
-// Implementation of the MainLoopBase class. It can monitor file descriptors
-// for readability using ppoll, kqueue, poll or WSAPoll. On Windows it only
-// supports polling sockets, and will not work on generic file handles or
-// pipes. On systems without kqueue or ppoll handling singnals is not
-// supported. In addition to the common base, this class provides the ability
-// to invoke a given handler when a signal is received.
-//
-// Since this class is primarily intended to be used for single-threaded
-// processing, it does not attempt to perform any internal synchronisation and
-// any concurrent accesses must be protected  externally. However, it is
-// perfectly legitimate to have more than one instance of this class running on
-// separate threads, or even a single thread (with some limitations on signal
-// monitoring).
-// TODO: Add locking if this class is to be used in a multi-threaded context.
-class MainLoop : public MainLoopBase {
-private:
-  class SignalHandle;
-
-public:
-  typedef std::unique_ptr<SignalHandle> SignalHandleUP;
-
-  MainLoop();
-  ~MainLoop() override;
-
-  ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp,
-                                  const Callback &callback,
-                                  Status &error) override;
-
-  // Listening for signals from multiple MainLoop instances is perfectly safe
-  // as long as they don't try to listen for the same signal. The callback
-  // function is invoked when the control returns to the Run() function, not
-  // when the hander is executed. This mean that you can treat the callback as
-  // a normal function and perform things which would not be safe in a signal
-  // handler. However, since the callback is not invoked synchronously, you
-  // cannot use this mechanism to handle SIGSEGV and the like.
-  SignalHandleUP RegisterSignal(int signo, const Callback &callback,
-                                Status &error);
-
-  // 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.
-  void AddPendingCallback(const Callback &callback) override;
-
-  Status Run() override;
-
-  // This should only be performed from a callback. Do not attempt to terminate
-  // the processing from another thread.
-  // TODO: Add synchronization if we want to be terminated from another thread.
-  void RequestTermination() override { m_terminate_request = true; }
-
-protected:
-  void UnregisterReadObject(IOObject::WaitableHandle handle) override;
-
-  void UnregisterSignal(int signo, std::list<Callback>::iterator callback_it);
-
-private:
-  void ProcessReadObject(IOObject::WaitableHandle handle);
-  void ProcessSignal(int signo);
-
-  class SignalHandle {
-  public:
-    ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo, m_callback_it); }
-
-  private:
-    SignalHandle(MainLoop &mainloop, int signo,
-                 std::list<Callback>::iterator callback_it)
-        : m_mainloop(mainloop), m_signo(signo), m_callback_it(callback_it) {}
-
-    MainLoop &m_mainloop;
-    int m_signo;
-    std::list<Callback>::iterator m_callback_it;
-
-    friend class MainLoop;
-    SignalHandle(const SignalHandle &) = delete;
-    const SignalHandle &operator=(const SignalHandle &) = delete;
-  };
-
-  struct SignalInfo {
-    std::list<Callback> callbacks;
-#ifndef SIGNAL_POLLING_UNSUPPORTED
-    struct sigaction old_action;
-#endif
-    bool was_blocked : 1;
-  };
-  class RunImpl;
-
-  llvm::DenseMap<IOObject::WaitableHandle, Callback> m_read_fds;
-  llvm::DenseMap<int, SignalInfo> m_signals;
-  std::vector<Callback> m_pending_callbacks;
-#if HAVE_SYS_EVENT_H
-  int m_kqueue;
+using MainLoop = MainLoopWindows;
+}
+#else
+#include "lldb/Host/posix/MainLoopPosix.h"
+namespace lldb_private {
+using MainLoop = MainLoopPosix;
+}
 #endif
-  bool m_terminate_request : 1;
-};
-
-} // namespace lldb_private
 
 #endif // LLDB_HOST_MAINLOOP_H
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to