LLDB mainline
MainLoopPosix.cpp
Go to the documentation of this file.
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
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
33using namespace lldb;
34using namespace lldb_private;
35
36namespace {
37struct 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
44static GlobalSignalInfo g_signal_info[NSIG];
45
46static 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
73public:
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
91private:
92 struct timespec m_ts;
93 struct timespec *m_ts_ptr;
94};
95
97public:
99 ~RunImpl() = default;
100
101 Status Poll();
102
103 void ProcessReadEvents();
104
105private:
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
120 in_events.reserve(loop.m_read_fds.size());
121}
122
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
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
160 read_fds.reserve(loop.m_read_fds.size());
161}
162
163static 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
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
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
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);
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
239#if HAVE_SYS_EVENT_H
240 close(m_kqueue);
241#endif
244 assert(m_read_fds.size() == 0);
245 assert(m_signals.size() == 0);
246}
247
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) {
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.
271MainLoopPosix::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!
291 g_signal_info[signo].flag = 0;
292
293 int ret = sigaction(signo, &new_action, &info.old_action);
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
307 bool erased = m_read_fds.erase(handle);
309 assert(erased);
310}
311
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);
331
332 m_signals.erase(it);
333 g_signal_info[signo] = {};
334}
335
337 m_terminate_request = false;
338
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
350
351 m_interrupting = false;
353 }
354 return Status();
355}
356
358 auto it = m_read_fds.find(handle);
359 if (it != m_read_fds.end())
360 it->second(*this); // Do the work
361}
362
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) {
371 return;
372
373 g_signal_info[signal].flag = 0;
374 ProcessSignal(signal);
375 }
376}
377
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
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());
399 assert(bytes_written == 1);
400}
static llvm::raw_ostream & error(Stream &strm)
static GlobalSignalInfo g_signal_info[NSIG]
static void SignalHandler(int signo, siginfo_t *info, void *)
static int StartPoll(llvm::MutableArrayRef< struct pollfd > fds, std::optional< MainLoopPosix::TimePoint > point)
std::vector< struct pollfd > read_fds
struct timespec * m_ts_ptr
ToTimeSpec & operator=(const ToTimeSpec &)=delete
ToTimeSpec(const ToTimeSpec &)=delete
ToTimeSpec(std::optional< MainLoopPosix::TimePoint > point)
struct timespec m_ts
std::unique_ptr< ReadHandle > ReadHandleUP
Definition: MainLoopBase.h:49
ReadHandleUP CreateReadHandle(const lldb::IOObjectSP &object_sp)
Definition: MainLoopBase.h:82
std::function< void(MainLoopBase &)> Callback
Definition: MainLoopBase.h:51
SignalHandleUP RegisterSignal(int signo, const Callback &callback, Status &error)
void UnregisterReadObject(IOObject::WaitableHandle handle) override
ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, const Callback &callback, Status &error) override
void ProcessReadObject(IOObject::WaitableHandle handle)
std::atomic< bool > m_interrupting
Definition: MainLoopPosix.h:92
llvm::DenseMap< int, SignalInfo > m_signals
Definition: MainLoopPosix.h:90
llvm::DenseMap< IOObject::WaitableHandle, Callback > m_read_fds
Definition: MainLoopPosix.h:89
std::unique_ptr< SignalHandle > SignalHandleUP
Definition: MainLoopPosix.h:32
void UnregisterSignal(int signo, std::list< Callback >::iterator callback_it)
Status Write(const void *buf, size_t size, size_t &bytes_written)
Definition: PipeBase.cpp:21
int GetReadFileDescriptor() const override
Definition: PipePosix.cpp:208
void Close() override
Definition: PipePosix.cpp:248
Status CreateNew(bool child_process_inherit) override
Definition: PipePosix.cpp:80
int GetWriteFileDescriptor() const override
Definition: PipePosix.cpp:217
An error handling class.
Definition: Status.h:118
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition: Status.cpp:106
static Status FromErrorString(const char *str)
Definition: Status.h:141
#define UNUSED_IF_ASSERT_DISABLED(x)
Definition: lldb-defines.h:140
A class that represents a running process on the host machine.
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::IOObject > IOObjectSP
Definition: lldb-forward.h:362
@ eErrorTypePOSIX
POSIX error codes.
#define O_NONBLOCK