llvm/lldb/source/Host/posix/MainLoopPosix.cpp

//===-- MainLoopPosix.cpp -------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "lldb/Host/posix/MainLoopPosix.h"
#include "lldb/Host/Config.h"
#include "lldb/Host/PosixApi.h"
#include "lldb/Utility/Status.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Errno.h"
#include <algorithm>
#include <cassert>
#include <cerrno>
#include <csignal>
#include <ctime>
#include <vector>

// Multiplexing is implemented using kqueue on systems that support it (BSD
// variants including OSX). On linux we use ppoll, while android uses pselect
// (ppoll is present but not implemented properly). On windows we use WSApoll
// (which does not support signals).

#if HAVE_SYS_EVENT_H
#include <sys/event.h>
#elif defined(__ANDROID__)
#include <sys/syscall.h>
#else
#include <poll.h>
#endif

usingnamespacelldb;
usingnamespacelldb_private;

static sig_atomic_t g_signal_flags[NSIG];

static void SignalHandler(int signo, siginfo_t *info, void *) {}

class MainLoopPosix::RunImpl {};

#if HAVE_SYS_EVENT_H
MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) : loop(loop) {
  in_events.reserve(loop.m_read_fds.size());
}

Status MainLoopPosix::RunImpl::Poll() {
  in_events.resize(loop.m_read_fds.size());
  unsigned i = 0;
  for (auto &fd : loop.m_read_fds)
    EV_SET(&in_events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);

  num_events = kevent(loop.m_kqueue, in_events.data(), in_events.size(),
                      out_events, std::size(out_events), nullptr);

  if (num_events < 0) {
    if (errno == EINTR) {
      // in case of EINTR, let the main loop run one iteration
      // we need to zero num_events to avoid assertions failing
      num_events = 0;
    } else
      return Status(errno, eErrorTypePOSIX);
  }
  return Status();
}

void MainLoopPosix::RunImpl::ProcessEvents() {
  assert(num_events >= 0);
  for (int i = 0; i < num_events; ++i) {
    if (loop.m_terminate_request)
      return;
    switch (out_events[i].filter) {
    case EVFILT_READ:
      loop.ProcessReadObject(out_events[i].ident);
      break;
    case EVFILT_SIGNAL:
      loop.ProcessSignal(out_events[i].ident);
      break;
    default:
      llvm_unreachable("Unknown event");
    }
  }
}
#else
MainLoopPosix::RunImpl::RunImpl(MainLoopPosix &loop) :{}

sigset_t MainLoopPosix::RunImpl::get_sigmask() {}

#ifdef __ANDROID__
Status MainLoopPosix::RunImpl::Poll() {
  // ppoll(2) is not supported on older all android versions. Also, older
  // versions android (API <= 19) implemented pselect in a non-atomic way, as a
  // combination of pthread_sigmask and select. This is not sufficient for us,
  // as we rely on the atomicity to correctly implement signal polling, so we
  // call the underlying syscall ourselves.

  FD_ZERO(&read_fd_set);
  int nfds = 0;
  for (const auto &fd : loop.m_read_fds) {
    FD_SET(fd.first, &read_fd_set);
    nfds = std::max(nfds, fd.first + 1);
  }

  union {
    sigset_t set;
    uint64_t pad;
  } kernel_sigset;
  memset(&kernel_sigset, 0, sizeof(kernel_sigset));
  kernel_sigset.set = get_sigmask();

  struct {
    void *sigset_ptr;
    size_t sigset_len;
  } extra_data = {&kernel_sigset, sizeof(kernel_sigset)};
  if (syscall(__NR_pselect6, nfds, &read_fd_set, nullptr, nullptr, nullptr,
              &extra_data) == -1) {
    if (errno != EINTR)
      return Status(errno, eErrorTypePOSIX);
    else
      FD_ZERO(&read_fd_set);
  }

  return Status();
}
#else
Status MainLoopPosix::RunImpl::Poll() {}
#endif

void MainLoopPosix::RunImpl::ProcessEvents() {}
#endif

MainLoopPosix::MainLoopPosix() :{}

MainLoopPosix::~MainLoopPosix() {}

MainLoopPosix::ReadHandleUP
MainLoopPosix::RegisterReadObject(const IOObjectSP &object_sp,
                                 const Callback &callback, Status &error) {}

// We shall block the signal, then install the signal handler. The signal will
// be unblocked in the Run() function to check for signal delivery.
MainLoopPosix::SignalHandleUP
MainLoopPosix::RegisterSignal(int signo, const Callback &callback,
                              Status &error) {}

void MainLoopPosix::UnregisterReadObject(IOObject::WaitableHandle handle) {}

void MainLoopPosix::UnregisterSignal(
    int signo, std::list<Callback>::iterator callback_it) {}

Status MainLoopPosix::Run() {}

void MainLoopPosix::ProcessReadObject(IOObject::WaitableHandle handle) {}

void MainLoopPosix::ProcessSignal(int signo) {}

void MainLoopPosix::TriggerPendingCallbacks() {}