MainLoop.cpp revision 317778
1//===-- MainLoop.cpp --------------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "llvm/Config/llvm-config.h"
11
12#include "lldb/Host/MainLoop.h"
13#include "lldb/Utility/Error.h"
14#include <algorithm>
15#include <cassert>
16#include <cerrno>
17#include <csignal>
18#include <vector>
19#include <time.h>
20
21#if HAVE_SYS_EVENT_H
22#include <sys/event.h>
23#elif defined(LLVM_ON_WIN32)
24#include <winsock2.h>
25#else
26#include <poll.h>
27#endif
28
29#ifdef LLVM_ON_WIN32
30#define POLL WSAPoll
31#else
32#define POLL poll
33#endif
34
35#ifdef __ANDROID__
36#define FORCE_PSELECT
37#endif
38
39#if SIGNAL_POLLING_UNSUPPORTED
40#ifdef LLVM_ON_WIN32
41typedef int sigset_t;
42typedef int siginfo_t;
43#endif
44
45int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout_ts,
46          const sigset_t *) {
47  int timeout =
48      (timeout_ts == nullptr)
49          ? -1
50          : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000);
51  return POLL(fds, nfds, timeout);
52}
53
54#endif
55
56using namespace lldb;
57using namespace lldb_private;
58
59static sig_atomic_t g_signal_flags[NSIG];
60
61static void SignalHandler(int signo, siginfo_t *info, void *) {
62  assert(signo < NSIG);
63  g_signal_flags[signo] = 1;
64}
65
66class MainLoop::RunImpl {
67public:
68  // TODO: Use llvm::Expected<T>
69  static std::unique_ptr<RunImpl> Create(MainLoop &loop, Error &error);
70  ~RunImpl();
71
72  Error Poll();
73
74  template <typename F> void ForEachReadFD(F &&f);
75  template <typename F> void ForEachSignal(F &&f);
76
77private:
78  MainLoop &loop;
79
80#if HAVE_SYS_EVENT_H
81  int queue_id;
82  std::vector<struct kevent> in_events;
83  struct kevent out_events[4];
84  int num_events = -1;
85
86  RunImpl(MainLoop &loop, int queue_id) : loop(loop), queue_id(queue_id) {
87    in_events.reserve(loop.m_read_fds.size() + loop.m_signals.size());
88  }
89#else
90  std::vector<int> signals;
91#ifdef FORCE_PSELECT
92  fd_set read_fd_set;
93#else
94  std::vector<struct pollfd> read_fds;
95#endif
96
97  RunImpl(MainLoop &loop) : loop(loop) {
98    signals.reserve(loop.m_signals.size());
99  }
100
101  sigset_t get_sigmask();
102#endif
103};
104
105#if HAVE_SYS_EVENT_H
106MainLoop::RunImpl::~RunImpl() {
107  int r = close(queue_id);
108  assert(r == 0);
109  (void)r;
110}
111std::unique_ptr<MainLoop::RunImpl> MainLoop::RunImpl::Create(MainLoop &loop, Error &error)
112{
113  error.Clear();
114  int queue_id = kqueue();
115  if(queue_id < 0) {
116    error = Error(errno, eErrorTypePOSIX);
117    return nullptr;
118  }
119  return std::unique_ptr<RunImpl>(new RunImpl(loop, queue_id));
120}
121
122Error MainLoop::RunImpl::Poll() {
123  in_events.resize(loop.m_read_fds.size() + loop.m_signals.size());
124  unsigned i = 0;
125  for (auto &fd : loop.m_read_fds)
126    EV_SET(&in_events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
127
128  for (const auto &sig : loop.m_signals)
129    EV_SET(&in_events[i++], sig.first, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
130
131  num_events = kevent(queue_id, in_events.data(), in_events.size(), out_events,
132                      llvm::array_lengthof(out_events), nullptr);
133
134  if (num_events < 0)
135    return Error("kevent() failed with error %d\n", num_events);
136  return Error();
137}
138
139template <typename F> void MainLoop::RunImpl::ForEachReadFD(F &&f) {
140  assert(num_events >= 0);
141  for (int i = 0; i < num_events; ++i) {
142    f(out_events[i].ident);
143    if (loop.m_terminate_request)
144      return;
145  }
146}
147template <typename F> void MainLoop::RunImpl::ForEachSignal(F && f) {}
148#else
149MainLoop::RunImpl::~RunImpl() {}
150std::unique_ptr<MainLoop::RunImpl> MainLoop::RunImpl::Create(MainLoop &loop, Error &error)
151{
152  error.Clear();
153  return std::unique_ptr<RunImpl>(new RunImpl(loop));
154}
155
156sigset_t MainLoop::RunImpl::get_sigmask() {
157#if SIGNAL_POLLING_UNSUPPORTED
158  return 0;
159#else
160  sigset_t sigmask;
161  int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask);
162  assert(ret == 0);
163  (void) ret;
164
165  for (const auto &sig : loop.m_signals) {
166    signals.push_back(sig.first);
167    sigdelset(&sigmask, sig.first);
168  }
169  return sigmask;
170#endif
171}
172
173#ifdef FORCE_PSELECT
174Error MainLoop::RunImpl::Poll() {
175  signals.clear();
176
177  FD_ZERO(&read_fd_set);
178  int nfds = 0;
179  for (const auto &fd : loop.m_read_fds) {
180    FD_SET(fd.first, &read_fd_set);
181    nfds = std::max(nfds, fd.first + 1);
182  }
183
184  sigset_t sigmask = get_sigmask();
185  if (pselect(nfds, &read_fd_set, nullptr, nullptr, nullptr, &sigmask) == -1 &&
186      errno != EINTR)
187    return Error(errno, eErrorTypePOSIX);
188
189  return Error();
190}
191
192template <typename F> void MainLoop::RunImpl::ForEachReadFD(F &&f) {
193  for (const auto &fd : loop.m_read_fds) {
194    if(!FD_ISSET(fd.first, &read_fd_set))
195      continue;
196
197    f(fd.first);
198    if (loop.m_terminate_request)
199      return;
200  }
201}
202#else
203Error MainLoop::RunImpl::Poll() {
204  signals.clear();
205  read_fds.clear();
206
207  sigset_t sigmask = get_sigmask();
208
209  for (const auto &fd : loop.m_read_fds) {
210    struct pollfd pfd;
211    pfd.fd = fd.first;
212    pfd.events = POLLIN;
213    pfd.revents = 0;
214    read_fds.push_back(pfd);
215  }
216
217  if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 &&
218      errno != EINTR)
219    return Error(errno, eErrorTypePOSIX);
220
221  return Error();
222}
223
224template <typename F> void MainLoop::RunImpl::ForEachReadFD(F &&f) {
225  for (const auto &fd : read_fds) {
226    if ((fd.revents & POLLIN) == 0)
227      continue;
228
229    f(fd.fd);
230    if (loop.m_terminate_request)
231      return;
232  }
233}
234#endif
235
236template <typename F> void MainLoop::RunImpl::ForEachSignal(F &&f) {
237  for (int sig : signals) {
238    if (g_signal_flags[sig] == 0)
239      continue; // No signal
240    g_signal_flags[sig] = 0;
241    f(sig);
242
243    if (loop.m_terminate_request)
244      return;
245  }
246}
247#endif
248
249MainLoop::~MainLoop() {
250  assert(m_read_fds.size() == 0);
251  assert(m_signals.size() == 0);
252}
253
254MainLoop::ReadHandleUP
255MainLoop::RegisterReadObject(const IOObjectSP &object_sp,
256                                  const Callback &callback, Error &error) {
257#ifdef LLVM_ON_WIN32
258  if (object_sp->GetFdType() != IOObject:: eFDTypeSocket) {
259    error.SetErrorString("MainLoop: non-socket types unsupported on Windows");
260    return nullptr;
261  }
262#endif
263  if (!object_sp || !object_sp->IsValid()) {
264    error.SetErrorString("IO object is not valid.");
265    return nullptr;
266  }
267
268  const bool inserted =
269      m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second;
270  if (!inserted) {
271    error.SetErrorStringWithFormat("File descriptor %d already monitored.",
272                                   object_sp->GetWaitableHandle());
273    return nullptr;
274  }
275
276  return CreateReadHandle(object_sp);
277}
278
279// We shall block the signal, then install the signal handler. The signal will
280// be unblocked in
281// the Run() function to check for signal delivery.
282MainLoop::SignalHandleUP
283MainLoop::RegisterSignal(int signo, const Callback &callback,
284                              Error &error) {
285#ifdef SIGNAL_POLLING_UNSUPPORTED
286  error.SetErrorString("Signal polling is not supported on this platform.");
287  return nullptr;
288#else
289  if (m_signals.find(signo) != m_signals.end()) {
290    error.SetErrorStringWithFormat("Signal %d already monitored.", signo);
291    return nullptr;
292  }
293
294  SignalInfo info;
295  info.callback = callback;
296  struct sigaction new_action;
297  new_action.sa_sigaction = &SignalHandler;
298  new_action.sa_flags = SA_SIGINFO;
299  sigemptyset(&new_action.sa_mask);
300  sigaddset(&new_action.sa_mask, signo);
301
302  sigset_t old_set;
303  if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set)) {
304    error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n",
305                                   ret);
306    return nullptr;
307  }
308
309  info.was_blocked = sigismember(&old_set, signo);
310  if (sigaction(signo, &new_action, &info.old_action) == -1) {
311    error.SetErrorToErrno();
312    if (!info.was_blocked)
313      pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr);
314    return nullptr;
315  }
316
317  m_signals.insert({signo, info});
318  g_signal_flags[signo] = 0;
319
320  return SignalHandleUP(new SignalHandle(*this, signo));
321#endif
322}
323
324void MainLoop::UnregisterReadObject(IOObject::WaitableHandle handle) {
325  bool erased = m_read_fds.erase(handle);
326  UNUSED_IF_ASSERT_DISABLED(erased);
327  assert(erased);
328}
329
330void MainLoop::UnregisterSignal(int signo) {
331#if SIGNAL_POLLING_UNSUPPORTED
332  Error("Signal polling is not supported on this platform.");
333#else
334  // We undo the actions of RegisterSignal on a best-effort basis.
335  auto it = m_signals.find(signo);
336  assert(it != m_signals.end());
337
338  sigaction(signo, &it->second.old_action, nullptr);
339
340  sigset_t set;
341  sigemptyset(&set);
342  sigaddset(&set, signo);
343  pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set,
344                  nullptr);
345
346  m_signals.erase(it);
347#endif
348}
349
350Error MainLoop::Run() {
351  m_terminate_request = false;
352
353  Error error;
354  auto impl = RunImpl::Create(*this, error);
355  if (!impl)
356    return error;
357
358  // run until termination or until we run out of things to listen to
359  while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) {
360
361    error = impl->Poll();
362    if (error.Fail())
363      return error;
364
365    impl->ForEachSignal([&](int sig) {
366      auto it = m_signals.find(sig);
367      if (it != m_signals.end())
368        it->second.callback(*this); // Do the work
369    });
370    if (m_terminate_request)
371      return Error();
372
373    impl->ForEachReadFD([&](int fd) {
374      auto it = m_read_fds.find(fd);
375      if (it != m_read_fds.end())
376        it->second(*this); // Do the work
377    });
378    if (m_terminate_request)
379      return Error();
380  }
381  return Error();
382}
383