10#include "lldb/Host/Config.h"
13#include "llvm/Config/llvm-config.h"
14#include "llvm/Support/Errno.h"
37struct GlobalSignalInfo {
38 sig_atomic_t pipe_fd = -1;
39 static_assert(
sizeof(sig_atomic_t) >=
sizeof(
int),
40 "Type too small for a file descriptor");
41 sig_atomic_t flag = 0;
65 ssize_t bytes_written = llvm::sys::RetryAfterSignal(-1, ::write, fd, &c, 1);
68 assert(bytes_written == 1 || (bytes_written == -1 && errno == EAGAIN));
74 explicit ToTimeSpec(std::optional<MainLoopPosix::TimePoint> point) {
75 using namespace std::chrono;
81 nanoseconds dur = std::max(*point - steady_clock::now(), nanoseconds(0));
83 m_ts.tv_sec = duration_cast<seconds>(dur).count();
84 m_ts.tv_nsec = (dur % seconds(1)).count();
89 operator struct timespec *() {
return m_ts_ptr; }
109 std::vector<struct kevent> in_events;
110 struct kevent out_events[4];
124 in_events.resize(loop.m_read_fds.size());
126 for (
auto &fd : loop.m_read_fds)
127 EV_SET(&in_events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
130 kevent(loop.m_kqueue, in_events.data(), in_events.size(), out_events,
131 std::size(out_events),
ToTimeSpec(loop.GetNextWakeupTime()));
133 if (num_events < 0) {
134 if (errno == EINTR) {
145 assert(num_events >= 0);
146 for (
int i = 0; i < num_events; ++i) {
147 if (loop.m_terminate_request)
149 switch (out_events[i].filter) {
151 loop.ProcessReadObject(out_events[i].ident);
154 llvm_unreachable(
"Unknown event");
163static int StartPoll(llvm::MutableArrayRef<struct pollfd> fds,
164 std::optional<MainLoopPosix::TimePoint> point) {
166 return ppoll(fds.data(), fds.size(),
ToTimeSpec(point),
169 using namespace std::chrono;
172 nanoseconds dur = std::max(*point - steady_clock::now(), nanoseconds(0));
173 timeout = ceil<milliseconds>(dur).count();
175 return poll(fds.data(), fds.size(), timeout);
182 for (
const auto &fd : loop.m_read_fds) {
187 read_fds.push_back(pfd);
189 int ready =
StartPoll(read_fds, loop.GetNextWakeupTime());
191 if (ready == -1 && errno != EINTR)
198 for (
const auto &fd : read_fds) {
199 if ((fd.revents & (POLLIN | POLLHUP)) == 0)
202 if (loop.m_terminate_request)
205 loop.ProcessReadObject(handle);
212 assert(
error.Success());
223 {interrupt_pipe_fd, [interrupt_pipe_fd](
MainLoopBase &loop) {
226 llvm::sys::RetryAfterSignal(-1, ::read, interrupt_pipe_fd, &c, 1);
227 assert(bytes_read == 1);
234 assert(m_kqueue >= 0);
251 if (!object_sp || !object_sp->IsValid()) {
256 const bool inserted =
257 m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second;
260 "File descriptor %d already monitored.",
261 object_sp->GetWaitableHandle());
275 auto callback_it = signal_it->second.callbacks.insert(
276 signal_it->second.callbacks.end(), callback);
282 struct sigaction new_action;
284 new_action.sa_flags = SA_SIGINFO;
285 sigemptyset(&new_action.sa_mask);
286 sigaddset(&new_action.sa_mask, signo);
293 int ret = sigaction(signo, &new_action, &info.
old_action);
295 assert(ret == 0 &&
"sigaction failed");
297 ret = pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, &old_set);
298 assert(ret == 0 &&
"pthread_sigmask failed");
300 auto insert_ret =
m_signals.insert({signo, info});
303 *
this, signo, insert_ret.first->second.callbacks.begin()));
313 int signo, std::list<Callback>::iterator callback_it) {
317 it->second.callbacks.erase(callback_it);
319 if (!it->second.callbacks.empty())
322 sigaction(signo, &it->second.old_action,
nullptr);
326 sigaddset(&set, signo);
327 int ret = pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK,
364 std::vector<int> signals;
367 signals.push_back(entry.first);
369 for (
const auto &signal : signals) {
383 llvm::SmallVector<Callback, 4> callbacks_to_run{
384 it->second.callbacks.begin(), it->second.callbacks.end()};
385 for (
auto &x : callbacks_to_run)
395 size_t bytes_written;
397 assert(
error.Success());
399 assert(bytes_written == 1);
static llvm::raw_ostream & error(Stream &strm)
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)
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
void Interrupt() override
llvm::DenseMap< IOObject::WaitableHandle, Callback > m_read_fds
void ProcessSignal(int signo)
std::unique_ptr< SignalHandle > SignalHandleUP
void UnregisterSignal(int signo, std::list< Callback >::iterator callback_it)
Status Write(const void *buf, size_t size, size_t &bytes_written)
int GetReadFileDescriptor() const override
Status CreateNew(bool child_process_inherit) override
int GetWriteFileDescriptor() const override
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.
std::shared_ptr< lldb_private::IOObject > IOObjectSP
@ eErrorTypePOSIX
POSIX error codes.
std::list< Callback > callbacks
struct sigaction old_action