mgorny updated this revision to Diff 453067.
mgorny added a comment.
Add `m_event_pipe` handler to `m_read_fds` to avoid reinventing the wheel three
times.
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,10 +7,12 @@
//===----------------------------------------------------------------------===//
#include "lldb/Host/posix/MainLoopPosix.h"
+
#include "lldb/Host/Config.h"
#include "lldb/Host/PosixApi.h"
#include "lldb/Utility/Status.h"
#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Errno.h"
#include <algorithm>
#include <cassert>
#include <cerrno>
@@ -222,6 +224,17 @@
#endif
MainLoopPosix::MainLoopPosix() {
+ Status error = m_event_pipe.CreateNew(/*child_process_inherit=*/false);
+ assert(error.Success());
+ const int event_pipe_fd = m_event_pipe.GetReadFileDescriptor();
+ m_read_fds.insert({event_pipe_fd, [this, event_pipe_fd](MainLoopBase &loop) {
+ 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);
+ ProcessEvents();
+ }});
#if HAVE_SYS_EVENT_H
m_kqueue = kqueue();
assert(m_kqueue >= 0);
@@ -232,6 +245,8 @@
#if HAVE_SYS_EVENT_H
close(m_kqueue);
#endif
+ m_read_fds.erase(m_event_pipe.GetReadFileDescriptor());
+ m_event_pipe.Close();
assert(m_signals.size() == 0);
}
@@ -321,7 +336,9 @@
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())) {
+ // (m_read_fds will always contain m_event_pipe fd, so check for > 1)
+ while (!m_terminate_request &&
+ (m_read_fds.size() > 1 || !m_signals.empty() || !m_events.empty())) {
error = impl.Poll();
if (error.Fail())
@@ -345,3 +362,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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits