xref: /llvm-project/lldb/source/Host/posix/MainLoopPosix.cpp (revision bca055f2ac075d43f6f316927947b2a493f93bdb)
1 //===-- MainLoopPosix.cpp -------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Host/posix/MainLoopPosix.h"
10 #include "lldb/Host/Config.h"
11 #include "lldb/Host/PosixApi.h"
12 #include "lldb/Utility/Status.h"
13 #include "llvm/Config/llvm-config.h"
14 #include "llvm/Support/Errno.h"
15 #include <algorithm>
16 #include <cassert>
17 #include <cerrno>
18 #include <chrono>
19 #include <csignal>
20 #include <ctime>
21 #include <fcntl.h>
22 #include <vector>
23 
24 // Multiplexing is implemented using kqueue on systems that support it (BSD
25 // variants including OSX). On linux we use ppoll.
26 
27 #if HAVE_SYS_EVENT_H
28 #include <sys/event.h>
29 #else
30 #include <poll.h>
31 #endif
32 
33 using namespace lldb;
34 using namespace lldb_private;
35 
36 namespace {
37 struct GlobalSignalInfo {
38   sig_atomic_t pipe_fd = -1;
39   static_assert(sizeof(sig_atomic_t) >= sizeof(int),
40                 "Type too small for a file descriptor");
41   sig_atomic_t flag = 0;
42 };
43 } // namespace
44 static GlobalSignalInfo g_signal_info[NSIG];
45 
46 static void SignalHandler(int signo, siginfo_t *info, void *) {
47   assert(signo < NSIG);
48 
49   // Set the flag before writing to the pipe!
50   g_signal_info[signo].flag = 1;
51 
52   int fd = g_signal_info[signo].pipe_fd;
53   if (fd < 0) {
54     // This can happen with the following (unlikely) sequence of events:
55     // 1. Thread 1 gets a signal, starts running the signal handler
56     // 2. Thread 2 unregisters the signal handler, setting pipe_fd to -1
57     // 3. Signal handler on thread 1 reads -1 out of pipe_fd
58     // In this case, we can just ignore the signal because we're no longer
59     // interested in it.
60     return;
61   }
62 
63   // Write a(ny) character to the pipe to wake up from the poll syscall.
64   char c = '.';
65   ssize_t bytes_written = llvm::sys::RetryAfterSignal(-1, ::write, fd, &c, 1);
66   // We can safely ignore EAGAIN (pipe full), as that means poll will definitely
67   // return.
68   assert(bytes_written == 1 || (bytes_written == -1 && errno == EAGAIN));
69   (void)bytes_written;
70 }
71 
72 class ToTimeSpec {
73 public:
74   explicit ToTimeSpec(std::optional<MainLoopPosix::TimePoint> point) {
75     using namespace std::chrono;
76 
77     if (!point) {
78       m_ts_ptr = nullptr;
79       return;
80     }
81     nanoseconds dur = std::max(*point - steady_clock::now(), nanoseconds(0));
82     m_ts_ptr = &m_ts;
83     m_ts.tv_sec = duration_cast<seconds>(dur).count();
84     m_ts.tv_nsec = (dur % seconds(1)).count();
85   }
86   ToTimeSpec(const ToTimeSpec &) = delete;
87   ToTimeSpec &operator=(const ToTimeSpec &) = delete;
88 
89   operator struct timespec *() { return m_ts_ptr; }
90 
91 private:
92   struct timespec m_ts;
93   struct timespec *m_ts_ptr;
94 };
95 
96 class MainLoopPosix::RunImpl {
97 public:
98   RunImpl(MainLoopPosix &loop);
99   ~RunImpl() = default;
100 
101   Status Poll();
102 
103   void ProcessReadEvents();
104 
105 private:
106   MainLoopPosix &loop;
107 
108 #if HAVE_SYS_EVENT_H
109   std::vector<struct kevent> in_events;
110   struct kevent out_events[4];
111   int num_events = -1;
112 
113 #else
114   std::vector<struct pollfd> read_fds;
115 #endif
116 };
117 
118 #if HAVE_SYS_EVENT_H
119 MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) {
120   in_events.reserve(loop.m_read_fds.size());
121 }
122 
123 Status MainLoopPosix::RunImpl::Poll() {
124   in_events.resize(loop.m_read_fds.size());
125   unsigned i = 0;
126   for (auto &fd : loop.m_read_fds)
127     EV_SET(&in_events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
128 
129   num_events =
130       kevent(loop.m_kqueue, in_events.data(), in_events.size(), out_events,
131              std::size(out_events), ToTimeSpec(loop.GetNextWakeupTime()));
132 
133   if (num_events < 0) {
134     if (errno == EINTR) {
135       // in case of EINTR, let the main loop run one iteration
136       // we need to zero num_events to avoid assertions failing
137       num_events = 0;
138     } else
139       return Status(errno, eErrorTypePOSIX);
140   }
141   return Status();
142 }
143 
144 void MainLoopPosix::RunImpl::ProcessReadEvents() {
145   assert(num_events >= 0);
146   for (int i = 0; i < num_events; ++i) {
147     if (loop.m_terminate_request)
148       return;
149     switch (out_events[i].filter) {
150     case EVFILT_READ:
151       loop.ProcessReadObject(out_events[i].ident);
152       break;
153     default:
154       llvm_unreachable("Unknown event");
155     }
156   }
157 }
158 #else
159 MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) {
160   read_fds.reserve(loop.m_read_fds.size());
161 }
162 
163 static int StartPoll(llvm::MutableArrayRef<struct pollfd> fds,
164                      std::optional<MainLoopPosix::TimePoint> point) {
165 #if HAVE_PPOLL
166   return ppoll(fds.data(), fds.size(), ToTimeSpec(point),
167                /*sigmask=*/nullptr);
168 #else
169   using namespace std::chrono;
170   int timeout = -1;
171   if (point) {
172     nanoseconds dur = std::max(*point - steady_clock::now(), nanoseconds(0));
173     timeout = ceil<milliseconds>(dur).count();
174   }
175   return poll(fds.data(), fds.size(), timeout);
176 #endif
177 }
178 
179 Status MainLoopPosix::RunImpl::Poll() {
180   read_fds.clear();
181 
182   for (const auto &fd : loop.m_read_fds) {
183     struct pollfd pfd;
184     pfd.fd = fd.first;
185     pfd.events = POLLIN;
186     pfd.revents = 0;
187     read_fds.push_back(pfd);
188   }
189   int ready = StartPoll(read_fds, loop.GetNextWakeupTime());
190 
191   if (ready == -1 && errno != EINTR)
192     return Status(errno, eErrorTypePOSIX);
193 
194   return Status();
195 }
196 
197 void MainLoopPosix::RunImpl::ProcessReadEvents() {
198   for (const auto &fd : read_fds) {
199     if ((fd.revents & (POLLIN | POLLHUP)) == 0)
200       continue;
201     IOObject::WaitableHandle handle = fd.fd;
202     if (loop.m_terminate_request)
203       return;
204 
205     loop.ProcessReadObject(handle);
206   }
207 }
208 #endif
209 
210 MainLoopPosix::MainLoopPosix() {
211   Status error = m_interrupt_pipe.CreateNew(/*child_process_inherit=*/false);
212   assert(error.Success());
213 
214   // Make the write end of the pipe non-blocking.
215   int result = fcntl(m_interrupt_pipe.GetWriteFileDescriptor(), F_SETFL,
216                      fcntl(m_interrupt_pipe.GetWriteFileDescriptor(), F_GETFL) |
217                          O_NONBLOCK);
218   assert(result == 0);
219   UNUSED_IF_ASSERT_DISABLED(result);
220 
221   const int interrupt_pipe_fd = m_interrupt_pipe.GetReadFileDescriptor();
222   m_read_fds.insert(
223       {interrupt_pipe_fd, [interrupt_pipe_fd](MainLoopBase &loop) {
224          char c;
225          ssize_t bytes_read =
226              llvm::sys::RetryAfterSignal(-1, ::read, interrupt_pipe_fd, &c, 1);
227          assert(bytes_read == 1);
228          UNUSED_IF_ASSERT_DISABLED(bytes_read);
229          // NB: This implicitly causes another loop iteration
230          // and therefore the execution of pending callbacks.
231        }});
232 #if HAVE_SYS_EVENT_H
233   m_kqueue = kqueue();
234   assert(m_kqueue >= 0);
235 #endif
236 }
237 
238 MainLoopPosix::~MainLoopPosix() {
239 #if HAVE_SYS_EVENT_H
240   close(m_kqueue);
241 #endif
242   m_read_fds.erase(m_interrupt_pipe.GetReadFileDescriptor());
243   m_interrupt_pipe.Close();
244   assert(m_read_fds.size() == 0);
245   assert(m_signals.size() == 0);
246 }
247 
248 MainLoopPosix::ReadHandleUP
249 MainLoopPosix::RegisterReadObject(const IOObjectSP &object_sp,
250                                   const Callback &callback, Status &error) {
251   if (!object_sp || !object_sp->IsValid()) {
252     error = Status::FromErrorString("IO object is not valid.");
253     return nullptr;
254   }
255 
256   const bool inserted =
257       m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second;
258   if (!inserted) {
259     error = Status::FromErrorStringWithFormat(
260         "File descriptor %d already monitored.",
261         object_sp->GetWaitableHandle());
262     return nullptr;
263   }
264 
265   return CreateReadHandle(object_sp);
266 }
267 
268 // We shall block the signal, then install the signal handler. The signal will
269 // be unblocked in the Run() function to check for signal delivery.
270 MainLoopPosix::SignalHandleUP
271 MainLoopPosix::RegisterSignal(int signo, const Callback &callback,
272                               Status &error) {
273   auto signal_it = m_signals.find(signo);
274   if (signal_it != m_signals.end()) {
275     auto callback_it = signal_it->second.callbacks.insert(
276         signal_it->second.callbacks.end(), callback);
277     return SignalHandleUP(new SignalHandle(*this, signo, callback_it));
278   }
279 
280   SignalInfo info;
281   info.callbacks.push_back(callback);
282   struct sigaction new_action;
283   new_action.sa_sigaction = &SignalHandler;
284   new_action.sa_flags = SA_SIGINFO;
285   sigemptyset(&new_action.sa_mask);
286   sigaddset(&new_action.sa_mask, signo);
287   sigset_t old_set;
288 
289   // Set signal info before installing the signal handler!
290   g_signal_info[signo].pipe_fd = m_interrupt_pipe.GetWriteFileDescriptor();
291   g_signal_info[signo].flag = 0;
292 
293   int ret = sigaction(signo, &new_action, &info.old_action);
294   UNUSED_IF_ASSERT_DISABLED(ret);
295   assert(ret == 0 && "sigaction failed");
296 
297   ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set);
298   assert(ret == 0 && "pthread_sigmask failed");
299   info.was_blocked = sigismember(&old_set, signo);
300   auto insert_ret = m_signals.insert({signo, info});
301 
302   return SignalHandleUP(new SignalHandle(
303       *this, signo, insert_ret.first->second.callbacks.begin()));
304 }
305 
306 void MainLoopPosix::UnregisterReadObject(IOObject::WaitableHandle handle) {
307   bool erased = m_read_fds.erase(handle);
308   UNUSED_IF_ASSERT_DISABLED(erased);
309   assert(erased);
310 }
311 
312 void MainLoopPosix::UnregisterSignal(
313     int signo, std::list<Callback>::iterator callback_it) {
314   auto it = m_signals.find(signo);
315   assert(it != m_signals.end());
316 
317   it->second.callbacks.erase(callback_it);
318   // Do not remove the signal handler unless all callbacks have been erased.
319   if (!it->second.callbacks.empty())
320     return;
321 
322   sigaction(signo, &it->second.old_action, nullptr);
323 
324   sigset_t set;
325   sigemptyset(&set);
326   sigaddset(&set, signo);
327   int ret = pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK,
328                             &set, nullptr);
329   assert(ret == 0);
330   UNUSED_IF_ASSERT_DISABLED(ret);
331 
332   m_signals.erase(it);
333   g_signal_info[signo] = {};
334 }
335 
336 Status MainLoopPosix::Run() {
337   m_terminate_request = false;
338 
339   Status error;
340   RunImpl impl(*this);
341 
342   while (!m_terminate_request) {
343     error = impl.Poll();
344     if (error.Fail())
345       return error;
346 
347     impl.ProcessReadEvents();
348 
349     ProcessSignals();
350 
351     m_interrupting = false;
352     ProcessCallbacks();
353   }
354   return Status();
355 }
356 
357 void MainLoopPosix::ProcessReadObject(IOObject::WaitableHandle handle) {
358   auto it = m_read_fds.find(handle);
359   if (it != m_read_fds.end())
360     it->second(*this); // Do the work
361 }
362 
363 void MainLoopPosix::ProcessSignals() {
364   std::vector<int> signals;
365   for (const auto &entry : m_signals)
366     if (g_signal_info[entry.first].flag != 0)
367       signals.push_back(entry.first);
368 
369   for (const auto &signal : signals) {
370     if (m_terminate_request)
371       return;
372 
373     g_signal_info[signal].flag = 0;
374     ProcessSignal(signal);
375   }
376 }
377 
378 void MainLoopPosix::ProcessSignal(int signo) {
379   auto it = m_signals.find(signo);
380   if (it != m_signals.end()) {
381     // The callback may actually register/unregister signal handlers,
382     // so we need to create a copy first.
383     llvm::SmallVector<Callback, 4> callbacks_to_run{
384         it->second.callbacks.begin(), it->second.callbacks.end()};
385     for (auto &x : callbacks_to_run)
386       x(*this); // Do the work
387   }
388 }
389 
390 void MainLoopPosix::Interrupt() {
391   if (m_interrupting.exchange(true))
392     return;
393 
394   char c = '.';
395   size_t bytes_written;
396   Status error = m_interrupt_pipe.Write(&c, 1, bytes_written);
397   assert(error.Success());
398   UNUSED_IF_ASSERT_DISABLED(error);
399   assert(bytes_written == 1);
400 }
401