10#include "lldb/Host/Config.h"
14#include "llvm/Config/llvm-config.h"
15#include "llvm/Support/Errno.h"
38struct GlobalSignalInfo {
39 sig_atomic_t pipe_fd = -1;
40 static_assert(
sizeof(sig_atomic_t) >=
sizeof(int),
41 "Type too small for a file descriptor");
42 sig_atomic_t flag = 0;
66 ssize_t bytes_written = llvm::sys::RetryAfterSignal(-1, ::write, fd, &c, 1);
69 assert(bytes_written == 1 || (bytes_written == -1 && errno == EAGAIN));
75 explicit ToTimeSpec(std::optional<MainLoopPosix::TimePoint> point) {
76 using namespace std::chrono;
82 nanoseconds dur = std::max(*point - steady_clock::now(), nanoseconds(0));
84 m_ts.tv_sec = duration_cast<seconds>(dur).count();
85 m_ts.tv_nsec = (dur % seconds(1)).count();
90 operator struct timespec *() {
return m_ts_ptr; }
110 std::vector<struct kevent> in_events;
111 struct kevent out_events[4];
125 in_events.resize(loop.m_read_fds.size());
127 for (
auto &fd : loop.m_read_fds)
128 EV_SET(&in_events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
131 kevent(loop.m_kqueue, in_events.data(), in_events.size(), out_events,
132 std::size(out_events),
ToTimeSpec(loop.GetNextWakeupTime()));
134 if (num_events < 0) {
135 if (errno == EINTR) {
146 assert(num_events >= 0);
147 for (
int i = 0; i < num_events; ++i) {
148 if (loop.m_terminate_request)
150 switch (out_events[i].filter) {
152 loop.ProcessReadObject(out_events[i].ident);
155 llvm_unreachable(
"Unknown event");
164static int StartPoll(llvm::MutableArrayRef<struct pollfd> fds,
165 std::optional<MainLoopPosix::TimePoint> point) {
167 return ppoll(fds.data(), fds.size(),
ToTimeSpec(point),
170 using namespace std::chrono;
173 nanoseconds dur = std::max(*point - steady_clock::now(), nanoseconds(0));
174 timeout = ceil<milliseconds>(dur).count();
176 return poll(fds.data(), fds.size(), timeout);
183 for (
const auto &fd :
loop.m_read_fds) {
192 if (ready == -1 && errno != EINTR)
200 if ((fd.revents & (POLLIN | POLLHUP)) == 0)
203 if (
loop.m_terminate_request)
206 loop.ProcessReadObject(handle);
213 assert(
error.Success());
224 {interrupt_pipe_fd, [interrupt_pipe_fd](
MainLoopBase &loop) {
227 llvm::sys::RetryAfterSignal(-1, ::read, interrupt_pipe_fd, &c, 1);
228 assert(bytes_read == 1);
235 assert(m_kqueue >= 0);
252 if (!object_sp || !object_sp->IsValid()) {
257 const bool inserted =
258 m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second;
261 "File descriptor %d already monitored.",
262 object_sp->GetWaitableHandle());
276 auto callback_it = signal_it->second.callbacks.insert(
277 signal_it->second.callbacks.end(), callback);
283 struct sigaction new_action;
285 new_action.sa_flags = SA_SIGINFO;
286 sigemptyset(&new_action.sa_mask);
287 sigaddset(&new_action.sa_mask, signo);
294 int ret = sigaction(signo, &new_action, &info.
old_action);
296 assert(ret == 0 &&
"sigaction failed");
298 ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set);
299 assert(ret == 0 &&
"pthread_sigmask failed");
301 auto insert_ret =
m_signals.insert({signo, info});
304 *
this, signo, insert_ret.first->second.callbacks.begin()));
314 int signo, std::list<Callback>::iterator callback_it) {
318 it->second.callbacks.erase(callback_it);
320 if (!it->second.callbacks.empty())
323 sigaction(signo, &it->second.old_action,
nullptr);
327 sigaddset(&set, signo);
328 int ret = pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK,
365 std::vector<int> signals;
368 signals.push_back(entry.first);
370 for (
const auto &signal : signals) {
384 llvm::SmallVector<Callback, 4> callbacks_to_run{
385 it->second.callbacks.begin(), it->second.callbacks.end()};
386 for (
auto &x : callbacks_to_run)
397 if (!result_or_err) {
399 "interrupt pipe write failed: {0}");
402 return *result_or_err != 0;
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG_ERROR(log, error,...)
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
RunImpl(MainLoopPosix &loop)
struct timespec * m_ts_ptr
ToTimeSpec & operator=(const ToTimeSpec &)=delete
ToTimeSpec(const ToTimeSpec &)=delete
ToTimeSpec(std::optional< MainLoopPosix::TimePoint > point)
lldb::file_t WaitableHandle
std::unique_ptr< ReadHandle > ReadHandleUP
ReadHandleUP CreateReadHandle(const lldb::IOObjectSP &object_sp)
std::function< void(MainLoopBase &)> Callback
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
llvm::DenseMap< int, SignalInfo > m_signals
~MainLoopPosix() override
llvm::DenseMap< IOObject::WaitableHandle, Callback > m_read_fds
void ProcessSignal(int signo)
bool Interrupt() override
Interrupt the loop that is currently waiting for events.
std::unique_ptr< SignalHandle > SignalHandleUP
void UnregisterSignal(int signo, std::list< Callback >::iterator callback_it)
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
static Status FromErrorString(const char *str)
#define UNUSED_IF_ASSERT_DISABLED(x)
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
std::shared_ptr< lldb_private::IOObject > IOObjectSP
@ eErrorTypePOSIX
POSIX error codes.
std::list< Callback > callbacks
struct sigaction old_action