[Lldb-commits] [lldb] r301636 - Resurrect pselect MainLoop implementation
Pavel Labath via lldb-commits
lldb-commits at lists.llvm.org
Fri Apr 28 03:26:06 PDT 2017
Author: labath
Date: Fri Apr 28 05:26:06 2017
New Revision: 301636
URL: http://llvm.org/viewvc/llvm-project?rev=301636&view=rev
Log:
Resurrect pselect MainLoop implementation
Summary:
It turns out that even though ppoll is available on all the android
devices we support, it does not seem to be working properly on all of
them -- MainLoop just does a busy loop with ppoll returning EINTR and
not making any progress.
This brings back the pselect implementation and makes it available on
android. I could not do any cmake checks for this as the ppoll symbol is
actually avaiable -- it just does not work.
Reviewers: beanz, eugene
Subscribers: srhines, lldb-commits
Differential Revision: https://reviews.llvm.org/D32600
Modified:
lldb/trunk/include/lldb/Host/MainLoop.h
lldb/trunk/source/Host/common/MainLoop.cpp
Modified: lldb/trunk/include/lldb/Host/MainLoop.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/MainLoop.h?rev=301636&r1=301635&r2=301636&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/MainLoop.h (original)
+++ lldb/trunk/include/lldb/Host/MainLoop.h Fri Apr 28 05:26:06 2017
@@ -93,6 +93,7 @@ private:
#endif
bool was_blocked : 1;
};
+ class RunImpl;
llvm::DenseMap<IOObject::WaitableHandle, Callback> m_read_fds;
llvm::DenseMap<int, SignalInfo> m_signals;
Modified: lldb/trunk/source/Host/common/MainLoop.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/MainLoop.cpp?rev=301636&r1=301635&r2=301636&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/MainLoop.cpp (original)
+++ lldb/trunk/source/Host/common/MainLoop.cpp Fri Apr 28 05:26:06 2017
@@ -32,6 +32,10 @@
#define POLL poll
#endif
+#ifdef __ANDROID__
+#define FORCE_PSELECT
+#endif
+
#if SIGNAL_POLLING_UNSUPPORTED
#ifdef LLVM_ON_WIN32
typedef int sigset_t;
@@ -59,6 +63,189 @@ static void SignalHandler(int signo, sig
g_signal_flags[signo] = 1;
}
+class MainLoop::RunImpl {
+public:
+ // TODO: Use llvm::Expected<T>
+ static std::unique_ptr<RunImpl> Create(MainLoop &loop, Error &error);
+ ~RunImpl();
+
+ Error Poll();
+
+ template <typename F> void ForEachReadFD(F &&f);
+ template <typename F> void ForEachSignal(F &&f);
+
+private:
+ MainLoop &loop;
+
+#if HAVE_SYS_EVENT_H
+ int queue_id;
+ std::vector<struct kevent> in_events;
+ struct kevent out_events[4];
+ int num_events = -1;
+
+ RunImpl(MainLoop &loop, int queue_id) : loop(loop), queue_id(queue_id) {
+ in_events.reserve(loop.m_read_fds.size() + loop.m_signals.size());
+ }
+#else
+ std::vector<int> signals;
+#ifdef FORCE_PSELECT
+ fd_set read_fd_set;
+#else
+ std::vector<struct pollfd> read_fds;
+#endif
+
+ RunImpl(MainLoop &loop) : loop(loop) {
+ signals.reserve(loop.m_signals.size());
+ }
+
+ sigset_t get_sigmask();
+#endif
+};
+
+#if HAVE_SYS_EVENT_H
+MainLoop::RunImpl::~RunImpl() {
+ int r = close(queue_id);
+ assert(r == 0);
+ (void)r;
+}
+std::unique_ptr<MainLoop::RunImpl> MainLoop::RunImpl::Create(MainLoop &loop, Error &error)
+{
+ error.Clear();
+ int queue_id = kqueue();
+ if(queue_id < 0) {
+ error = Error(errno, eErrorTypePOSIX);
+ return nullptr;
+ }
+ return std::unique_ptr<RunImpl>(new RunImpl(loop, queue_id));
+}
+
+Error MainLoop::RunImpl::Poll() {
+ in_events.resize(loop.m_read_fds.size() + loop.m_signals.size());
+ unsigned i = 0;
+ for (auto &fd : loop.m_read_fds)
+ EV_SET(&in_events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
+
+ for (const auto &sig : loop.m_signals)
+ EV_SET(&in_events[i++], sig.first, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
+
+ num_events = kevent(queue_id, in_events.data(), in_events.size(), out_events,
+ llvm::array_lengthof(out_events), nullptr);
+
+ if (num_events < 0)
+ return Error("kevent() failed with error %d\n", num_events);
+ return Error();
+}
+
+template <typename F> void MainLoop::RunImpl::ForEachReadFD(F &&f) {
+ assert(num_events >= 0);
+ for (int i = 0; i < num_events; ++i) {
+ f(out_events[i].ident);
+ if (loop.m_terminate_request)
+ return;
+ }
+}
+template <typename F> void MainLoop::RunImpl::ForEachSignal(F && f) {}
+#else
+MainLoop::RunImpl::~RunImpl() {}
+std::unique_ptr<MainLoop::RunImpl> MainLoop::RunImpl::Create(MainLoop &loop, Error &error)
+{
+ error.Clear();
+ return std::unique_ptr<RunImpl>(new RunImpl(loop));
+}
+
+sigset_t MainLoop::RunImpl::get_sigmask() {
+#if SIGNAL_POLLING_UNSUPPORTED
+ return 0;
+#else
+ sigset_t sigmask;
+ int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask);
+ assert(ret == 0);
+ (void) ret;
+
+ for (const auto &sig : loop.m_signals) {
+ signals.push_back(sig.first);
+ sigdelset(&sigmask, sig.first);
+ }
+ return sigmask;
+#endif
+}
+
+#ifdef FORCE_PSELECT
+Error MainLoop::RunImpl::Poll() {
+ signals.clear();
+
+ FD_ZERO(&read_fd_set);
+ int nfds = 0;
+ for (const auto &fd : loop.m_read_fds) {
+ FD_SET(fd.first, &read_fd_set);
+ nfds = std::max(nfds, fd.first + 1);
+ }
+
+ sigset_t sigmask = get_sigmask();
+ if (pselect(nfds, &read_fd_set, nullptr, nullptr, nullptr, &sigmask) == -1 &&
+ errno != EINTR)
+ return Error(errno, eErrorTypePOSIX);
+
+ return Error();
+}
+
+template <typename F> void MainLoop::RunImpl::ForEachReadFD(F &&f) {
+ for (const auto &fd : loop.m_read_fds) {
+ if(!FD_ISSET(fd.first, &read_fd_set))
+ continue;
+
+ f(fd.first);
+ if (loop.m_terminate_request)
+ return;
+ }
+}
+#else
+Error MainLoop::RunImpl::Poll() {
+ signals.clear();
+ read_fds.clear();
+
+ sigset_t sigmask = get_sigmask();
+
+ for (const auto &fd : loop.m_read_fds) {
+ struct pollfd pfd;
+ pfd.fd = fd.first;
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ read_fds.push_back(pfd);
+ }
+
+ if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 &&
+ errno != EINTR)
+ return Error(errno, eErrorTypePOSIX);
+
+ return Error();
+}
+
+template <typename F> void MainLoop::RunImpl::ForEachReadFD(F &&f) {
+ for (const auto &fd : read_fds) {
+ if ((fd.revents & POLLIN) == 0)
+ continue;
+
+ f(fd.fd);
+ if (loop.m_terminate_request)
+ return;
+ }
+}
+#endif
+
+template <typename F> void MainLoop::RunImpl::ForEachSignal(F &&f) {
+ for (int sig : signals) {
+ if (g_signal_flags[sig] == 0)
+ continue; // No signal
+ g_signal_flags[sig] = 0;
+ f(sig);
+
+ if (loop.m_terminate_request)
+ return;
+ }
+}
+#endif
+
MainLoop::~MainLoop() {
assert(m_read_fds.size() == 0);
assert(m_signals.size() == 0);
@@ -161,108 +348,35 @@ void MainLoop::UnregisterSignal(int sign
}
Error MainLoop::Run() {
- std::vector<int> signals;
m_terminate_request = false;
- signals.reserve(m_signals.size());
-#if HAVE_SYS_EVENT_H
- int queue_id = kqueue();
- if (queue_id < 0)
- Error("kqueue failed with error %d\n", queue_id);
-
- std::vector<struct kevent> events;
- events.reserve(m_read_fds.size() + m_signals.size());
-#else
- sigset_t sigmask;
- std::vector<struct pollfd> read_fds;
- read_fds.reserve(m_read_fds.size());
-#endif
+ Error error;
+ auto impl = RunImpl::Create(*this, error);
+ if (!impl)
+ return error;
// run until termination or until we run out of things to listen to
while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) {
- // To avoid problems with callbacks changing the things we're supposed to
- // listen to, we
- // will store the *real* list of events separately.
- signals.clear();
-#if HAVE_SYS_EVENT_H
- events.resize(m_read_fds.size() + m_signals.size());
- int i = 0;
- for (auto &fd: m_read_fds) {
- EV_SET(&events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
- }
-
- for (const auto &sig : m_signals) {
- signals.push_back(sig.first);
- EV_SET(&events[i++], sig.first, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
- }
-
- struct kevent event_list[4];
- int num_events =
- kevent(queue_id, events.data(), events.size(), event_list, 4, NULL);
-
- if (num_events < 0)
- return Error("kevent() failed with error %d\n", num_events);
-
-#else
- read_fds.clear();
-
-#if !SIGNAL_POLLING_UNSUPPORTED
- if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask))
- return Error("pthread_sigmask failed with error %d\n", ret);
-
- for (const auto &sig : m_signals) {
- signals.push_back(sig.first);
- sigdelset(&sigmask, sig.first);
- }
-#endif
-
- for (const auto &fd : m_read_fds) {
- struct pollfd pfd;
- pfd.fd = fd.first;
- pfd.events = POLLIN;
- pfd.revents = 0;
- read_fds.push_back(pfd);
- }
-
- if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 &&
- errno != EINTR)
- return Error(errno, eErrorTypePOSIX);
-#endif
-
- for (int sig : signals) {
- if (g_signal_flags[sig] == 0)
- continue; // No signal
- g_signal_flags[sig] = 0;
+ error = impl->Poll();
+ if (error.Fail())
+ return error;
+ impl->ForEachSignal([&](int sig) {
auto it = m_signals.find(sig);
- if (it == m_signals.end())
- continue; // Signal must have gotten unregistered in the meantime
-
- it->second.callback(*this); // Do the work
-
- if (m_terminate_request)
- return Error();
- }
-
-#if HAVE_SYS_EVENT_H
- for (int i = 0; i < num_events; ++i) {
- auto it = m_read_fds.find(event_list[i].ident);
-#else
- for (auto fd : read_fds) {
- if ((fd.revents & POLLIN) == 0)
- continue;
-
- auto it = m_read_fds.find(fd.fd);
-#endif
- if (it == m_read_fds.end())
- continue; // File descriptor must have gotten unregistered in the
- // meantime
- it->second(*this); // Do the work
-
- if (m_terminate_request)
- return Error();
- }
+ if (it != m_signals.end())
+ it->second.callback(*this); // Do the work
+ });
+ if (m_terminate_request)
+ return Error();
+
+ impl->ForEachReadFD([&](int fd) {
+ auto it = m_read_fds.find(fd);
+ if (it != m_read_fds.end())
+ it->second(*this); // Do the work
+ });
+ if (m_terminate_request)
+ return Error();
}
return Error();
}
More information about the lldb-commits
mailing list