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/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 #if !HAVE_PPOLL && !HAVE_SYS_EVENT_H
36 
37 int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout_ts,
38           const sigset_t *) {
39   int timeout =
40       (timeout_ts == nullptr)
41           ? -1
42           : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000);
43   return POLL(fds, nfds, timeout);
44 }
45 
46 #endif
47 
48 using namespace lldb;
49 using namespace lldb_private;
50 
51 static sig_atomic_t g_signal_flags[NSIG];
52 
53 static void SignalHandler(int signo, siginfo_t *info, void *) {
54   assert(signo < NSIG);
55   g_signal_flags[signo] = 1;
56 }
57 
58 MainLoop::~MainLoop() {
59   assert(m_read_fds.size() == 0);
60   assert(m_signals.size() == 0);
61 }
62 
63 MainLoop::ReadHandleUP
64 MainLoop::RegisterReadObject(const IOObjectSP &object_sp,
65                                   const Callback &callback, Error &error) {
66 #ifdef LLVM_ON_WIN32
67   if (object_sp->GetFdType() != IOObject:: eFDTypeSocket) {
68     error.SetErrorString("MainLoop: non-socket types unsupported on Windows");
69     return nullptr;
70   }
71 #endif
72   if (!object_sp || !object_sp->IsValid()) {
73     error.SetErrorString("IO object is not valid.");
74     return nullptr;
75   }
76 
77   const bool inserted =
78       m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second;
79   if (!inserted) {
80     error.SetErrorStringWithFormat("File descriptor %d already monitored.",
81                                    object_sp->GetWaitableHandle());
82     return nullptr;
83   }
84 
85   return CreateReadHandle(object_sp);
86 }
87 
88 // We shall block the signal, then install the signal handler. The signal will
89 // be unblocked in
90 // the Run() function to check for signal delivery.
91 MainLoop::SignalHandleUP
92 MainLoop::RegisterSignal(int signo, const Callback &callback,
93                               Error &error) {
94 #ifdef SIGNAL_POLLING_UNSUPPORTED
95   error.SetErrorString("Signal polling is not supported on this platform.");
96   return nullptr;
97 #else
98   if (m_signals.find(signo) != m_signals.end()) {
99     error.SetErrorStringWithFormat("Signal %d already monitored.", signo);
100     return nullptr;
101   }
102 
103   SignalInfo info;
104   info.callback = callback;
105   struct sigaction new_action;
106   new_action.sa_sigaction = &SignalHandler;
107   new_action.sa_flags = SA_SIGINFO;
108   sigemptyset(&new_action.sa_mask);
109   sigaddset(&new_action.sa_mask, signo);
110 
111   sigset_t old_set;
112   if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set)) {
113     error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n",
114                                    ret);
115     return nullptr;
116   }
117 
118   info.was_blocked = sigismember(&old_set, signo);
119   if (sigaction(signo, &new_action, &info.old_action) == -1) {
120     error.SetErrorToErrno();
121     if (!info.was_blocked)
122       pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr);
123     return nullptr;
124   }
125 
126   m_signals.insert({signo, info});
127   g_signal_flags[signo] = 0;
128 
129   return SignalHandleUP(new SignalHandle(*this, signo));
130 #endif
131 }
132 
133 void MainLoop::UnregisterReadObject(IOObject::WaitableHandle handle) {
134   bool erased = m_read_fds.erase(handle);
135   UNUSED_IF_ASSERT_DISABLED(erased);
136   assert(erased);
137 }
138 
139 void MainLoop::UnregisterSignal(int signo) {
140   // We undo the actions of RegisterSignal on a best-effort basis.
141   auto it = m_signals.find(signo);
142   assert(it != m_signals.end());
143 
144   sigaction(signo, &it->second.old_action, nullptr);
145 
146   sigset_t set;
147   sigemptyset(&set);
148   sigaddset(&set, signo);
149   pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set,
150                   nullptr);
151 
152   m_signals.erase(it);
153 }
154 
155 Error MainLoop::Run() {
156   std::vector<int> signals;
157   m_terminate_request = false;
158   signals.reserve(m_signals.size());
159 
160 #if HAVE_SYS_EVENT_H
161   int queue_id = kqueue();
162   if (queue_id < 0)
163     Error("kqueue failed with error %d\n", queue_id);
164 
165   std::vector<struct kevent> events;
166   events.reserve(m_read_fds.size() + m_signals.size());
167 #else
168   sigset_t sigmask;
169   std::vector<struct pollfd> read_fds;
170   read_fds.reserve(m_read_fds.size());
171 #endif
172 
173   // run until termination or until we run out of things to listen to
174   while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) {
175     // To avoid problems with callbacks changing the things we're supposed to
176     // listen to, we
177     // will store the *real* list of events separately.
178     signals.clear();
179 
180 #if HAVE_SYS_EVENT_H
181     events.resize(m_read_fds.size() + m_signals.size());
182     int i = 0;
183     for (auto &fd: m_read_fds) {
184       EV_SET(&events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
185     }
186 
187     for (const auto &sig : m_signals) {
188       signals.push_back(sig.first);
189       EV_SET(&events[i++], sig.first, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
190     }
191 
192     struct kevent event_list[4];
193     int num_events =
194         kevent(queue_id, events.data(), events.size(), event_list, 4, NULL);
195 
196     if (num_events < 0)
197       return Error("kevent() failed with error %d\n", num_events);
198 
199 #else
200     read_fds.clear();
201     if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask))
202       return Error("pthread_sigmask failed with error %d\n", ret);
203 
204     for (const auto &fd : m_read_fds) {
205       struct pollfd pfd;
206       pfd.fd = fd.first;
207       pfd.events = POLLIN;
208       pfd.revents = 0;
209       read_fds.push_back(pfd);
210     }
211 
212     for (const auto &sig : m_signals) {
213       signals.push_back(sig.first);
214       sigdelset(&sigmask, sig.first);
215     }
216 
217     if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 &&
218         errno != EINTR)
219       return Error(errno, eErrorTypePOSIX);
220 #endif
221 
222     for (int sig : signals) {
223       if (g_signal_flags[sig] == 0)
224         continue; // No signal
225       g_signal_flags[sig] = 0;
226 
227       auto it = m_signals.find(sig);
228       if (it == m_signals.end())
229         continue; // Signal must have gotten unregistered in the meantime
230 
231       it->second.callback(*this); // Do the work
232 
233       if (m_terminate_request)
234         return Error();
235     }
236 
237 #if HAVE_SYS_EVENT_H
238     for (int i = 0; i < num_events; ++i) {
239       auto it = m_read_fds.find(event_list[i].ident);
240 #else
241     for (auto fd : read_fds) {
242       if ((fd.revents & POLLIN) == 0)
243         continue;
244 
245       auto it = m_read_fds.find(fd.fd);
246 #endif
247       if (it == m_read_fds.end())
248         continue; // File descriptor must have gotten unregistered in the
249                   // meantime
250       it->second(*this); // Do the work
251 
252       if (m_terminate_request)
253         return Error();
254     }
255   }
256   return Error();
257 }
258