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