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