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