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
SignalHandler(int signo,siginfo_t * info,void *)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:
ToTimeSpec(std::optional<MainLoopPosix::TimePoint> point)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
operator struct timespec*()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
RunImpl(MainLoopPosix & loop)119 MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) {
120 in_events.reserve(loop.m_read_fds.size());
121 }
122
Poll()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
ProcessReadEvents()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
RunImpl(MainLoopPosix & loop)159 MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) {
160 read_fds.reserve(loop.m_read_fds.size());
161 }
162
StartPoll(llvm::MutableArrayRef<struct pollfd> fds,std::optional<MainLoopPosix::TimePoint> point)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
Poll()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
ProcessReadEvents()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
MainLoopPosix()210 MainLoopPosix::MainLoopPosix() {
211 Status error = m_interrupt_pipe.CreateNew();
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
~MainLoopPosix()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
RegisterReadObject(const IOObjectSP & object_sp,const Callback & callback,Status & error)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
RegisterSignal(int signo,const Callback & callback,Status & error)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
UnregisterReadObject(IOObject::WaitableHandle handle)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
UnregisterSignal(int signo,std::list<Callback>::iterator callback_it)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
Run()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
ProcessReadObject(IOObject::WaitableHandle handle)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
ProcessSignals()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
ProcessSignal(int signo)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
Interrupt()390 void MainLoopPosix::Interrupt() {
391 if (m_interrupting.exchange(true))
392 return;
393
394 char c = '.';
395 cantFail(m_interrupt_pipe.Write(&c, 1));
396 }
397