/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Host/posix/MainLoopPosix.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
35 | | using namespace lldb; |
36 | | using namespace lldb_private; |
37 | | |
38 | | static sig_atomic_t g_signal_flags[NSIG]; |
39 | | |
40 | 5 | static void SignalHandler(int signo, siginfo_t *info, void *) { |
41 | 5 | assert(signo < NSIG); |
42 | 5 | g_signal_flags[signo] = 1; |
43 | 5 | } |
44 | | |
45 | | class MainLoopPosix::RunImpl { |
46 | | public: |
47 | | RunImpl(MainLoopPosix &loop); |
48 | 62 | ~RunImpl() = default; |
49 | | |
50 | | Status Poll(); |
51 | | void ProcessEvents(); |
52 | | |
53 | | private: |
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 |
73 | 62 | MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) { |
74 | 62 | in_events.reserve(loop.m_read_fds.size()); |
75 | 62 | } |
76 | | |
77 | 63 | Status MainLoopPosix::RunImpl::Poll() { |
78 | 63 | in_events.resize(loop.m_read_fds.size()); |
79 | 63 | unsigned i = 0; |
80 | 63 | for (auto &fd : loop.m_read_fds) |
81 | 162 | EV_SET(&in_events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0); |
82 | | |
83 | 63 | num_events = kevent(loop.m_kqueue, in_events.data(), in_events.size(), |
84 | 63 | out_events, std::size(out_events), nullptr); |
85 | | |
86 | 63 | if (num_events < 0) { |
87 | 0 | 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 | 0 | num_events = 0; |
91 | 0 | } else |
92 | 0 | return Status(errno, eErrorTypePOSIX); |
93 | 0 | } |
94 | 63 | return Status(); |
95 | 63 | } |
96 | | |
97 | 63 | void MainLoopPosix::RunImpl::ProcessEvents() { |
98 | 63 | assert(num_events >= 0); |
99 | 126 | for (int i = 0; 63 i < num_events; ++i63 ) { |
100 | 64 | if (loop.m_terminate_request) |
101 | 1 | return; |
102 | 63 | switch (out_events[i].filter) { |
103 | 58 | case EVFILT_READ: |
104 | 58 | loop.ProcessReadObject(out_events[i].ident); |
105 | 58 | break; |
106 | 5 | case EVFILT_SIGNAL: |
107 | 5 | loop.ProcessSignal(out_events[i].ident); |
108 | 5 | break; |
109 | 0 | default: |
110 | 0 | llvm_unreachable("Unknown event"); |
111 | 63 | } |
112 | 63 | } |
113 | 63 | } |
114 | | #else |
115 | | MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) { |
116 | | #ifndef __ANDROID__ |
117 | | read_fds.reserve(loop.m_read_fds.size()); |
118 | | #endif |
119 | | } |
120 | | |
121 | | sigset_t MainLoopPosix::RunImpl::get_sigmask() { |
122 | | sigset_t sigmask; |
123 | | int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask); |
124 | | assert(ret == 0); |
125 | | (void)ret; |
126 | | |
127 | | for (const auto &sig : loop.m_signals) |
128 | | sigdelset(&sigmask, sig.first); |
129 | | return sigmask; |
130 | | } |
131 | | |
132 | | #ifdef __ANDROID__ |
133 | | Status 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 |
169 | | Status 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(pfd); |
180 | | } |
181 | | |
182 | | if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 && |
183 | | errno != EINTR) |
184 | | return Status(errno, eErrorTypePOSIX); |
185 | | |
186 | | return Status(); |
187 | | } |
188 | | #endif |
189 | | |
190 | | void 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(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(signal); |
224 | | } |
225 | | } |
226 | | #endif |
227 | | |
228 | 64 | MainLoopPosix::MainLoopPosix() : m_triggering(false) { |
229 | 64 | Status error = m_trigger_pipe.CreateNew(/*child_process_inherit=*/false); |
230 | 64 | assert(error.Success()); |
231 | 64 | const int trigger_pipe_fd = m_trigger_pipe.GetReadFileDescriptor(); |
232 | 64 | m_read_fds.insert({trigger_pipe_fd, [trigger_pipe_fd](MainLoopBase &loop) { |
233 | 2 | char c; |
234 | 2 | ssize_t bytes_read = llvm::sys::RetryAfterSignal( |
235 | 2 | -1, ::read, trigger_pipe_fd, &c, 1); |
236 | 2 | assert(bytes_read == 1); |
237 | 2 | UNUSED_IF_ASSERT_DISABLED(bytes_read); |
238 | | // NB: This implicitly causes another loop iteration |
239 | | // and therefore the execution of pending callbacks. |
240 | 2 | }}); |
241 | 64 | #if HAVE_SYS_EVENT_H |
242 | 64 | m_kqueue = kqueue(); |
243 | 64 | assert(m_kqueue >= 0); |
244 | 64 | #endif |
245 | 64 | } |
246 | | |
247 | 64 | MainLoopPosix::~MainLoopPosix() { |
248 | 64 | #if HAVE_SYS_EVENT_H |
249 | 64 | close(m_kqueue); |
250 | 64 | #endif |
251 | 64 | m_read_fds.erase(m_trigger_pipe.GetReadFileDescriptor()); |
252 | 64 | m_trigger_pipe.Close(); |
253 | 64 | assert(m_read_fds.size() == 0); |
254 | 64 | assert(m_signals.size() == 0); |
255 | 64 | } |
256 | | |
257 | | MainLoopPosix::ReadHandleUP |
258 | | MainLoopPosix::RegisterReadObject(const IOObjectSP &object_sp, |
259 | 97 | const Callback &callback, Status &error) { |
260 | 97 | if (!object_sp || !object_sp->IsValid()) { |
261 | 0 | error.SetErrorString("IO object is not valid."); |
262 | 0 | return nullptr; |
263 | 0 | } |
264 | | |
265 | 97 | const bool inserted = |
266 | 97 | m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second; |
267 | 97 | if (!inserted) { |
268 | 0 | error.SetErrorStringWithFormat("File descriptor %d already monitored.", |
269 | 0 | object_sp->GetWaitableHandle()); |
270 | 0 | return nullptr; |
271 | 0 | } |
272 | | |
273 | 97 | return CreateReadHandle(object_sp); |
274 | 97 | } |
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. |
278 | | MainLoopPosix::SignalHandleUP |
279 | | MainLoopPosix::RegisterSignal(int signo, const Callback &callback, |
280 | 9 | Status &error) { |
281 | 9 | auto signal_it = m_signals.find(signo); |
282 | 9 | if (signal_it != m_signals.end()) { |
283 | 2 | auto callback_it = signal_it->second.callbacks.insert( |
284 | 2 | signal_it->second.callbacks.end(), callback); |
285 | 2 | return SignalHandleUP(new SignalHandle(*this, signo, callback_it)); |
286 | 2 | } |
287 | | |
288 | 7 | SignalInfo info; |
289 | 7 | info.callbacks.push_back(callback); |
290 | 7 | struct sigaction new_action; |
291 | 7 | new_action.sa_sigaction = &SignalHandler; |
292 | 7 | new_action.sa_flags = SA_SIGINFO; |
293 | 7 | sigemptyset(&new_action.sa_mask); |
294 | 7 | sigaddset(&new_action.sa_mask, signo); |
295 | 7 | sigset_t old_set; |
296 | | |
297 | 7 | 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 | 7 | int ret = sigaction(signo, &new_action, &info.old_action); |
302 | 7 | (void)ret; |
303 | 7 | assert(ret == 0 && "sigaction failed"); |
304 | | |
305 | 7 | #if HAVE_SYS_EVENT_H |
306 | 7 | struct kevent ev; |
307 | 7 | EV_SET(&ev, signo, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); |
308 | 7 | ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr); |
309 | 7 | assert(ret == 0); |
310 | 7 | #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 | 7 | ret = pthread_sigmask(HAVE_SYS_EVENT_H ? SIG_UNBLOCK : SIG_BLOCK, |
316 | 7 | &new_action.sa_mask, &old_set); |
317 | 7 | assert(ret == 0 && "pthread_sigmask failed"); |
318 | 7 | info.was_blocked = sigismember(&old_set, signo); |
319 | 7 | auto insert_ret = m_signals.insert({signo, info}); |
320 | | |
321 | 7 | return SignalHandleUP(new SignalHandle( |
322 | 7 | *this, signo, insert_ret.first->second.callbacks.begin())); |
323 | 7 | } |
324 | | |
325 | 97 | void MainLoopPosix::UnregisterReadObject(IOObject::WaitableHandle handle) { |
326 | 97 | bool erased = m_read_fds.erase(handle); |
327 | 97 | UNUSED_IF_ASSERT_DISABLED(erased); |
328 | 97 | assert(erased); |
329 | 97 | } |
330 | | |
331 | | void MainLoopPosix::UnregisterSignal( |
332 | 9 | int signo, std::list<Callback>::iterator callback_it) { |
333 | 9 | auto it = m_signals.find(signo); |
334 | 9 | assert(it != m_signals.end()); |
335 | | |
336 | 9 | it->second.callbacks.erase(callback_it); |
337 | | // Do not remove the signal handler unless all callbacks have been erased. |
338 | 9 | if (!it->second.callbacks.empty()) |
339 | 2 | return; |
340 | | |
341 | 7 | sigaction(signo, &it->second.old_action, nullptr); |
342 | | |
343 | 7 | sigset_t set; |
344 | 7 | sigemptyset(&set); |
345 | 7 | sigaddset(&set, signo); |
346 | 7 | int ret = pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, |
347 | 7 | &set, nullptr); |
348 | 7 | assert(ret == 0); |
349 | 7 | (void)ret; |
350 | | |
351 | 7 | #if HAVE_SYS_EVENT_H |
352 | 7 | struct kevent ev; |
353 | 7 | EV_SET(&ev, signo, EVFILT_SIGNAL, EV_DELETE, 0, 0, 0); |
354 | 7 | ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr); |
355 | 7 | assert(ret == 0); |
356 | 7 | #endif |
357 | | |
358 | 7 | m_signals.erase(it); |
359 | 7 | } |
360 | | |
361 | 62 | Status MainLoopPosix::Run() { |
362 | 62 | m_terminate_request = false; |
363 | | |
364 | 62 | Status error; |
365 | 62 | 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 | 125 | while (!m_terminate_request && |
370 | 125 | (64 m_read_fds.size() > 164 || !m_signals.empty()6 )) { |
371 | 63 | error = impl.Poll(); |
372 | 63 | if (error.Fail()) |
373 | 0 | return error; |
374 | | |
375 | 63 | impl.ProcessEvents(); |
376 | | |
377 | 63 | m_triggering = false; |
378 | 63 | ProcessPendingCallbacks(); |
379 | 63 | } |
380 | 62 | return Status(); |
381 | 62 | } |
382 | | |
383 | 58 | void MainLoopPosix::ProcessReadObject(IOObject::WaitableHandle handle) { |
384 | 58 | auto it = m_read_fds.find(handle); |
385 | 58 | if (it != m_read_fds.end()) |
386 | 58 | it->second(*this); // Do the work |
387 | 58 | } |
388 | | |
389 | 5 | void MainLoopPosix::ProcessSignal(int signo) { |
390 | 5 | auto it = m_signals.find(signo); |
391 | 5 | if (it != m_signals.end()) { |
392 | | // The callback may actually register/unregister signal handlers, |
393 | | // so we need to create a copy first. |
394 | 5 | llvm::SmallVector<Callback, 4> callbacks_to_run{ |
395 | 5 | it->second.callbacks.begin(), it->second.callbacks.end()}; |
396 | 5 | for (auto &x : callbacks_to_run) |
397 | 7 | x(*this); // Do the work |
398 | 5 | } |
399 | 5 | } |
400 | | |
401 | 65.5k | void MainLoopPosix::TriggerPendingCallbacks() { |
402 | 65.5k | if (m_triggering.exchange(true)) |
403 | 65.5k | return; |
404 | | |
405 | 5 | char c = '.'; |
406 | 5 | size_t bytes_written; |
407 | 5 | Status error = m_trigger_pipe.Write(&c, 1, bytes_written); |
408 | 5 | assert(error.Success()); |
409 | 5 | UNUSED_IF_ASSERT_DISABLED(error); |
410 | 5 | assert(bytes_written == 1); |
411 | 5 | } |