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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits