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