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 <csignal>
19#include <ctime>
20#include <vector>
21
22// Multiplexing is implemented using kqueue on systems that support it (BSD
23// variants including OSX). On linux we use ppoll, while android uses pselect
24// (ppoll is present but not implemented properly). On windows we use WSApoll
25// (which does not support signals).
26
27#if HAVE_SYS_EVENT_H
28#include <sys/event.h>
29#elif defined(__ANDROID__)
30#include <sys/syscall.h>
31#else
32#include <poll.h>
33#endif
34
35using namespace lldb;
36using namespace lldb_private;
37
38static sig_atomic_t g_signal_flags[NSIG];
39
40static void SignalHandler(int signo, siginfo_t *info, void *) {
41 assert(signo < NSIG);
42 g_signal_flags[signo] = 1;
43}
44
45class MainLoopPosix::RunImpl {
46public:
47 RunImpl(MainLoopPosix &loop);
48 ~RunImpl() = default;
49
50 Status Poll();
51 void ProcessEvents();
52
53private:
54 MainLoopPosix &loop;
55
56#if HAVE_SYS_EVENT_H
57 std::vector<struct kevent> in_events;
58 struct kevent out_events[4];
59 int num_events = -1;
60
61#else
62#ifdef __ANDROID__
63 fd_set read_fd_set;
64#else
65 std::vector<struct pollfd> read_fds;
66#endif
67
68 sigset_t get_sigmask();
69#endif
70};
71
72#if HAVE_SYS_EVENT_H
73MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) {
74 in_events.reserve(loop.m_read_fds.size());
75}
76
77Status MainLoopPosix::RunImpl::Poll() {
78 in_events.resize(loop.m_read_fds.size());
79 unsigned i = 0;
80 for (auto &fd : loop.m_read_fds)
81 EV_SET(&in_events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
82
83 num_events = kevent(loop.m_kqueue, in_events.data(), in_events.size(),
84 out_events, std::size(out_events), nullptr);
85
86 if (num_events < 0) {
87 if (errno == EINTR) {
88 // in case of EINTR, let the main loop run one iteration
89 // we need to zero num_events to avoid assertions failing
90 num_events = 0;
91 } else
92 return Status(errno, eErrorTypePOSIX);
93 }
94 return Status();
95}
96
97void MainLoopPosix::RunImpl::ProcessEvents() {
98 assert(num_events >= 0);
99 for (int i = 0; i < num_events; ++i) {
100 if (loop.m_terminate_request)
101 return;
102 switch (out_events[i].filter) {
103 case EVFILT_READ:
104 loop.ProcessReadObject(out_events[i].ident);
105 break;
106 case EVFILT_SIGNAL:
107 loop.ProcessSignal(out_events[i].ident);
108 break;
109 default:
110 llvm_unreachable("Unknown event");
111 }
112 }
113}
114#else
115MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) {
116#ifndef __ANDROID__
117 read_fds.reserve(n: loop.m_read_fds.size());
118#endif
119}
120
121sigset_t MainLoopPosix::RunImpl::get_sigmask() {
122 sigset_t sigmask;
123 int ret = pthread_sigmask(SIG_SETMASK, newmask: nullptr, oldmask: &sigmask);
124 assert(ret == 0);
125 UNUSED_IF_ASSERT_DISABLED(ret);
126
127 for (const auto &sig : loop.m_signals)
128 sigdelset(set: &sigmask, signo: sig.first);
129 return sigmask;
130}
131
132#ifdef __ANDROID__
133Status MainLoopPosix::RunImpl::Poll() {
134 // ppoll(2) is not supported on older all android versions. Also, older
135 // versions android (API <= 19) implemented pselect in a non-atomic way, as a
136 // combination of pthread_sigmask and select. This is not sufficient for us,
137 // as we rely on the atomicity to correctly implement signal polling, so we
138 // call the underlying syscall ourselves.
139
140 FD_ZERO(&read_fd_set);
141 int nfds = 0;
142 for (const auto &fd : loop.m_read_fds) {
143 FD_SET(fd.first, &read_fd_set);
144 nfds = std::max(nfds, fd.first + 1);
145 }
146
147 union {
148 sigset_t set;
149 uint64_t pad;
150 } kernel_sigset;
151 memset(&kernel_sigset, 0, sizeof(kernel_sigset));
152 kernel_sigset.set = get_sigmask();
153
154 struct {
155 void *sigset_ptr;
156 size_t sigset_len;
157 } extra_data = {&kernel_sigset, sizeof(kernel_sigset)};
158 if (syscall(__NR_pselect6, nfds, &read_fd_set, nullptr, nullptr, nullptr,
159 &extra_data) == -1) {
160 if (errno != EINTR)
161 return Status(errno, eErrorTypePOSIX);
162 else
163 FD_ZERO(&read_fd_set);
164 }
165
166 return Status();
167}
168#else
169Status MainLoopPosix::RunImpl::Poll() {
170 read_fds.clear();
171
172 sigset_t sigmask = get_sigmask();
173
174 for (const auto &fd : loop.m_read_fds) {
175 struct pollfd pfd;
176 pfd.fd = fd.first;
177 pfd.events = POLLIN;
178 pfd.revents = 0;
179 read_fds.push_back(x: pfd);
180 }
181
182 if (ppoll(fds: read_fds.data(), nfds: read_fds.size(), timeout: nullptr, ss: &sigmask) == -1 &&
183 errno != EINTR)
184 return Status(errno, eErrorTypePOSIX);
185
186 return Status();
187}
188#endif
189
190void MainLoopPosix::RunImpl::ProcessEvents() {
191#ifdef __ANDROID__
192 // Collect first all readable file descriptors into a separate vector and
193 // then iterate over it to invoke callbacks. Iterating directly over
194 // loop.m_read_fds is not possible because the callbacks can modify the
195 // container which could invalidate the iterator.
196 std::vector<IOObject::WaitableHandle> fds;
197 for (const auto &fd : loop.m_read_fds)
198 if (FD_ISSET(fd.first, &read_fd_set))
199 fds.push_back(fd.first);
200
201 for (const auto &handle : fds) {
202#else
203 for (const auto &fd : read_fds) {
204 if ((fd.revents & (POLLIN | POLLHUP)) == 0)
205 continue;
206 IOObject::WaitableHandle handle = fd.fd;
207#endif
208 if (loop.m_terminate_request)
209 return;
210
211 loop.ProcessReadObject(handle);
212 }
213
214 std::vector<int> signals;
215 for (const auto &entry : loop.m_signals)
216 if (g_signal_flags[entry.first] != 0)
217 signals.push_back(x: entry.first);
218
219 for (const auto &signal : signals) {
220 if (loop.m_terminate_request)
221 return;
222 g_signal_flags[signal] = 0;
223 loop.ProcessSignal(signo: signal);
224 }
225}
226#endif
227
228MainLoopPosix::MainLoopPosix() : m_triggering(false) {
229 Status error = m_trigger_pipe.CreateNew(/*child_process_inherit=*/false);
230 assert(error.Success());
231 const int trigger_pipe_fd = m_trigger_pipe.GetReadFileDescriptor();
232 m_read_fds.insert(KV: {trigger_pipe_fd, [trigger_pipe_fd](MainLoopBase &loop) {
233 char c;
234 ssize_t bytes_read = llvm::sys::RetryAfterSignal(
235 Fail: -1, F&: ::read, As: trigger_pipe_fd, As: &c, As: 1);
236 assert(bytes_read == 1);
237 UNUSED_IF_ASSERT_DISABLED(bytes_read);
238 // NB: This implicitly causes another loop iteration
239 // and therefore the execution of pending callbacks.
240 }});
241#if HAVE_SYS_EVENT_H
242 m_kqueue = kqueue();
243 assert(m_kqueue >= 0);
244#endif
245}
246
247MainLoopPosix::~MainLoopPosix() {
248#if HAVE_SYS_EVENT_H
249 close(m_kqueue);
250#endif
251 m_read_fds.erase(Val: m_trigger_pipe.GetReadFileDescriptor());
252 m_trigger_pipe.Close();
253 assert(m_read_fds.size() == 0);
254 assert(m_signals.size() == 0);
255}
256
257MainLoopPosix::ReadHandleUP
258MainLoopPosix::RegisterReadObject(const IOObjectSP &object_sp,
259 const Callback &callback, Status &error) {
260 if (!object_sp || !object_sp->IsValid()) {
261 error.SetErrorString("IO object is not valid.");
262 return nullptr;
263 }
264
265 const bool inserted =
266 m_read_fds.insert(KV: {object_sp->GetWaitableHandle(), callback}).second;
267 if (!inserted) {
268 error.SetErrorStringWithFormat("File descriptor %d already monitored.",
269 object_sp->GetWaitableHandle());
270 return nullptr;
271 }
272
273 return CreateReadHandle(object_sp);
274}
275
276// We shall block the signal, then install the signal handler. The signal will
277// be unblocked in the Run() function to check for signal delivery.
278MainLoopPosix::SignalHandleUP
279MainLoopPosix::RegisterSignal(int signo, const Callback &callback,
280 Status &error) {
281 auto signal_it = m_signals.find(Val: signo);
282 if (signal_it != m_signals.end()) {
283 auto callback_it = signal_it->second.callbacks.insert(
284 position: signal_it->second.callbacks.end(), x: callback);
285 return SignalHandleUP(new SignalHandle(*this, signo, callback_it));
286 }
287
288 SignalInfo info;
289 info.callbacks.push_back(x: callback);
290 struct sigaction new_action;
291 new_action.sa_sigaction = &SignalHandler;
292 new_action.sa_flags = SA_SIGINFO;
293 sigemptyset(set: &new_action.sa_mask);
294 sigaddset(set: &new_action.sa_mask, signo: signo);
295 sigset_t old_set;
296
297 g_signal_flags[signo] = 0;
298
299 // Even if using kqueue, the signal handler will still be invoked, so it's
300 // important to replace it with our "benign" handler.
301 int ret = sigaction(sig: signo, act: &new_action, oact: &info.old_action);
302 UNUSED_IF_ASSERT_DISABLED(ret);
303 assert(ret == 0 && "sigaction failed");
304
305#if HAVE_SYS_EVENT_H
306 struct kevent ev;
307 EV_SET(&ev, signo, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
308 ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr);
309 assert(ret == 0);
310#endif
311
312 // If we're using kqueue, the signal needs to be unblocked in order to
313 // receive it. If using pselect/ppoll, we need to block it, and later unblock
314 // it as a part of the system call.
315 ret = pthread_sigmask(HAVE_SYS_EVENT_H ? SIG_UNBLOCK : SIG_BLOCK,
316 newmask: &new_action.sa_mask, oldmask: &old_set);
317 assert(ret == 0 && "pthread_sigmask failed");
318 info.was_blocked = sigismember(set: &old_set, signo: signo);
319 auto insert_ret = m_signals.insert(KV: {signo, info});
320
321 return SignalHandleUP(new SignalHandle(
322 *this, signo, insert_ret.first->second.callbacks.begin()));
323}
324
325void MainLoopPosix::UnregisterReadObject(IOObject::WaitableHandle handle) {
326 bool erased = m_read_fds.erase(Val: handle);
327 UNUSED_IF_ASSERT_DISABLED(erased);
328 assert(erased);
329}
330
331void MainLoopPosix::UnregisterSignal(
332 int signo, std::list<Callback>::iterator callback_it) {
333 auto it = m_signals.find(Val: signo);
334 assert(it != m_signals.end());
335
336 it->second.callbacks.erase(position: callback_it);
337 // Do not remove the signal handler unless all callbacks have been erased.
338 if (!it->second.callbacks.empty())
339 return;
340
341 sigaction(sig: signo, act: &it->second.old_action, oact: nullptr);
342
343 sigset_t set;
344 sigemptyset(set: &set);
345 sigaddset(set: &set, signo: signo);
346 int ret = pthread_sigmask(how: it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK,
347 newmask: &set, oldmask: nullptr);
348 assert(ret == 0);
349 UNUSED_IF_ASSERT_DISABLED(ret);
350
351#if HAVE_SYS_EVENT_H
352 struct kevent ev;
353 EV_SET(&ev, signo, EVFILT_SIGNAL, EV_DELETE, 0, 0, 0);
354 ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr);
355 assert(ret == 0);
356#endif
357
358 m_signals.erase(I: it);
359}
360
361Status MainLoopPosix::Run() {
362 m_terminate_request = false;
363
364 Status error;
365 RunImpl impl(*this);
366
367 // run until termination or until we run out of things to listen to
368 // (m_read_fds will always contain m_trigger_pipe fd, so check for > 1)
369 while (!m_terminate_request &&
370 (m_read_fds.size() > 1 || !m_signals.empty())) {
371 error = impl.Poll();
372 if (error.Fail())
373 return error;
374
375 impl.ProcessEvents();
376
377 m_triggering = false;
378 ProcessPendingCallbacks();
379 }
380 return Status();
381}
382
383void MainLoopPosix::ProcessReadObject(IOObject::WaitableHandle handle) {
384 auto it = m_read_fds.find(Val: handle);
385 if (it != m_read_fds.end())
386 it->second(*this); // Do the work
387}
388
389void MainLoopPosix::ProcessSignal(int signo) {
390 auto it = m_signals.find(Val: signo);
391 if (it != m_signals.end()) {
392 // The callback may actually register/unregister signal handlers,
393 // so we need to create a copy first.
394 llvm::SmallVector<Callback, 4> callbacks_to_run{
395 it->second.callbacks.begin(), it->second.callbacks.end()};
396 for (auto &x : callbacks_to_run)
397 x(*this); // Do the work
398 }
399}
400
401void MainLoopPosix::TriggerPendingCallbacks() {
402 if (m_triggering.exchange(i: true))
403 return;
404
405 char c = '.';
406 size_t bytes_written;
407 Status error = m_trigger_pipe.Write(buf: &c, size: 1, bytes_written);
408 assert(error.Success());
409 UNUSED_IF_ASSERT_DISABLED(error);
410 assert(bytes_written == 1);
411}
412

source code of lldb/source/Host/posix/MainLoopPosix.cpp