labath created this revision.
Herald added a subscriber: srhines.
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.
I haven't tested (or even built) this yet on platforms other than linux,
but I wanted to share this early to get feedback on the way I abstract
the pselect/ppoll/kevent implementations.
https://reviews.llvm.org/D32600
Files:
include/lldb/Host/MainLoop.h
source/Host/common/MainLoop.cpp
Index: source/Host/common/MainLoop.cpp
===================================================================
--- source/Host/common/MainLoop.cpp
+++ source/Host/common/MainLoop.cpp
@@ -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,165 @@
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> events;
+ struct kevent event_list[4];
+ int num_events = -1;
+
+ RunImpl(MainLoop &loop, int queue_id) : loop(loop), queue_id(queue_id) {
+ events.reserve(loop.m_read_fds.size() + loop.m_signals.size());
+ }
+#else
+ sigset_t sigmask;
+ std::vector<int> signals;
+ std::vector<struct pollfd> read_fds;
+
+ RunImpl(MainLoop &loop) : loop(loop) {
+ read_fds.reserve(loop.m_read_fds.size());
+ signals.reserve(loop.m_signals.size());
+ }
+#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() {
+ events.resize(loop.m_read_fds.size() + loop.m_signals.size());
+ unsigned i = 0;
+ for (auto &fd : loop.m_read_fds)
+ EV_SET(&events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
+
+ for (const auto &sig : loop.m_signals)
+ EV_SET(&events[i++], sig.first, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
+
+ num_events = kevent(queue_id, events.data(), events.size(), event_list,
+ llvm::array_lengthof(event_list), 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(event_list[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));
+}
+
+Error MainLoop::RunImpl::Poll() {
+ // 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();
+ 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 : loop.m_signals) {
+ signals.push_back(sig.first);
+ sigdelset(&sigmask, sig.first);
+ }
+#endif
+
+#ifdef FORCE_PSELECT
+ fd_set read_fd_set;
+ FD_ZERO(&read_fd_set);
+ int nfds = 0;
+#endif
+
+ 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);
+#ifdef FORCE_PSELECT
+ FD_SET(fd.first, &read_fd_set);
+ nfds = std::max(nfds, fd.first + 1);
+#endif
+ }
+
+#ifdef FORCE_PSELECT
+ if (pselect(nfds, &read_fd_set, nullptr, nullptr, nullptr, &sigmask) == -1 &&
+ errno != EINTR)
+ return Error(errno, eErrorTypePOSIX);
+ for (auto &fd : read_fds) {
+ if(FD_ISSET(fd.fd, &read_fd_set))
+ fd.revents = POLLIN;
+ }
+#else
+ if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 &&
+ errno != EINTR)
+ return Error(errno, eErrorTypePOSIX);
+#endif
+
+ 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;
+ }
+}
+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 +324,35 @@
}
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();
}
Index: include/lldb/Host/MainLoop.h
===================================================================
--- include/lldb/Host/MainLoop.h
+++ include/lldb/Host/MainLoop.h
@@ -93,6 +93,7 @@
#endif
bool was_blocked : 1;
};
+ class RunImpl;
llvm::DenseMap<IOObject::WaitableHandle, Callback> m_read_fds;
llvm::DenseMap<int, SignalInfo> m_signals;
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits