1 //===-- MainLoop.cpp --------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/Config/config.h" 11 12 #include "lldb/Host/MainLoop.h" 13 #include "lldb/Utility/Error.h" 14 #include <algorithm> 15 #include <cassert> 16 #include <cerrno> 17 #include <csignal> 18 #include <vector> 19 #include <time.h> 20 21 #if HAVE_SYS_EVENT_H 22 #include <sys/event.h> 23 #elif defined(LLVM_ON_WIN32) 24 #include <winsock2.h> 25 #else 26 #include <poll.h> 27 #endif 28 29 #ifdef LLVM_ON_WIN32 30 #define POLL WSAPoll 31 #else 32 #define POLL poll 33 #endif 34 35 #if !HAVE_PPOLL && !HAVE_SYS_EVENT_H 36 37 int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout_ts, 38 const sigset_t *) { 39 int timeout = 40 (timeout_ts == nullptr) 41 ? -1 42 : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000); 43 return POLL(fds, nfds, timeout); 44 } 45 46 #endif 47 48 using namespace lldb; 49 using namespace lldb_private; 50 51 static sig_atomic_t g_signal_flags[NSIG]; 52 53 static void SignalHandler(int signo, siginfo_t *info, void *) { 54 assert(signo < NSIG); 55 g_signal_flags[signo] = 1; 56 } 57 58 MainLoop::~MainLoop() { 59 assert(m_read_fds.size() == 0); 60 assert(m_signals.size() == 0); 61 } 62 63 MainLoop::ReadHandleUP 64 MainLoop::RegisterReadObject(const IOObjectSP &object_sp, 65 const Callback &callback, Error &error) { 66 #ifdef LLVM_ON_WIN32 67 if (object_sp->GetFdType() != IOObject:: eFDTypeSocket) { 68 error.SetErrorString("MainLoop: non-socket types unsupported on Windows"); 69 return nullptr; 70 } 71 #endif 72 if (!object_sp || !object_sp->IsValid()) { 73 error.SetErrorString("IO object is not valid."); 74 return nullptr; 75 } 76 77 const bool inserted = 78 m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second; 79 if (!inserted) { 80 error.SetErrorStringWithFormat("File descriptor %d already monitored.", 81 object_sp->GetWaitableHandle()); 82 return nullptr; 83 } 84 85 return CreateReadHandle(object_sp); 86 } 87 88 // We shall block the signal, then install the signal handler. The signal will 89 // be unblocked in 90 // the Run() function to check for signal delivery. 91 MainLoop::SignalHandleUP 92 MainLoop::RegisterSignal(int signo, const Callback &callback, 93 Error &error) { 94 #ifdef SIGNAL_POLLING_UNSUPPORTED 95 error.SetErrorString("Signal polling is not supported on this platform."); 96 return nullptr; 97 #else 98 if (m_signals.find(signo) != m_signals.end()) { 99 error.SetErrorStringWithFormat("Signal %d already monitored.", signo); 100 return nullptr; 101 } 102 103 SignalInfo info; 104 info.callback = callback; 105 struct sigaction new_action; 106 new_action.sa_sigaction = &SignalHandler; 107 new_action.sa_flags = SA_SIGINFO; 108 sigemptyset(&new_action.sa_mask); 109 sigaddset(&new_action.sa_mask, signo); 110 111 sigset_t old_set; 112 if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set)) { 113 error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n", 114 ret); 115 return nullptr; 116 } 117 118 info.was_blocked = sigismember(&old_set, signo); 119 if (sigaction(signo, &new_action, &info.old_action) == -1) { 120 error.SetErrorToErrno(); 121 if (!info.was_blocked) 122 pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr); 123 return nullptr; 124 } 125 126 m_signals.insert({signo, info}); 127 g_signal_flags[signo] = 0; 128 129 return SignalHandleUP(new SignalHandle(*this, signo)); 130 #endif 131 } 132 133 void MainLoop::UnregisterReadObject(IOObject::WaitableHandle handle) { 134 bool erased = m_read_fds.erase(handle); 135 UNUSED_IF_ASSERT_DISABLED(erased); 136 assert(erased); 137 } 138 139 void MainLoop::UnregisterSignal(int signo) { 140 // We undo the actions of RegisterSignal on a best-effort basis. 141 auto it = m_signals.find(signo); 142 assert(it != m_signals.end()); 143 144 sigaction(signo, &it->second.old_action, nullptr); 145 146 sigset_t set; 147 sigemptyset(&set); 148 sigaddset(&set, signo); 149 pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set, 150 nullptr); 151 152 m_signals.erase(it); 153 } 154 155 Error MainLoop::Run() { 156 std::vector<int> signals; 157 m_terminate_request = false; 158 signals.reserve(m_signals.size()); 159 160 #if HAVE_SYS_EVENT_H 161 int queue_id = kqueue(); 162 if (queue_id < 0) 163 Error("kqueue failed with error %d\n", queue_id); 164 165 std::vector<struct kevent> events; 166 events.reserve(m_read_fds.size() + m_signals.size()); 167 #else 168 sigset_t sigmask; 169 std::vector<struct pollfd> read_fds; 170 read_fds.reserve(m_read_fds.size()); 171 #endif 172 173 // run until termination or until we run out of things to listen to 174 while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) { 175 // To avoid problems with callbacks changing the things we're supposed to 176 // listen to, we 177 // will store the *real* list of events separately. 178 signals.clear(); 179 180 #if HAVE_SYS_EVENT_H 181 events.resize(m_read_fds.size() + m_signals.size()); 182 int i = 0; 183 for (auto &fd: m_read_fds) { 184 EV_SET(&events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0); 185 } 186 187 for (const auto &sig : m_signals) { 188 signals.push_back(sig.first); 189 EV_SET(&events[i++], sig.first, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); 190 } 191 192 struct kevent event_list[4]; 193 int num_events = 194 kevent(queue_id, events.data(), events.size(), event_list, 4, NULL); 195 196 if (num_events < 0) 197 return Error("kevent() failed with error %d\n", num_events); 198 199 #else 200 read_fds.clear(); 201 if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask)) 202 return Error("pthread_sigmask failed with error %d\n", ret); 203 204 for (const auto &fd : 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 for (const auto &sig : m_signals) { 213 signals.push_back(sig.first); 214 sigdelset(&sigmask, sig.first); 215 } 216 217 if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 && 218 errno != EINTR) 219 return Error(errno, eErrorTypePOSIX); 220 #endif 221 222 for (int sig : signals) { 223 if (g_signal_flags[sig] == 0) 224 continue; // No signal 225 g_signal_flags[sig] = 0; 226 227 auto it = m_signals.find(sig); 228 if (it == m_signals.end()) 229 continue; // Signal must have gotten unregistered in the meantime 230 231 it->second.callback(*this); // Do the work 232 233 if (m_terminate_request) 234 return Error(); 235 } 236 237 #if HAVE_SYS_EVENT_H 238 for (int i = 0; i < num_events; ++i) { 239 auto it = m_read_fds.find(event_list[i].ident); 240 #else 241 for (auto fd : read_fds) { 242 if ((fd.revents & POLLIN) == 0) 243 continue; 244 245 auto it = m_read_fds.find(fd.fd); 246 #endif 247 if (it == m_read_fds.end()) 248 continue; // File descriptor must have gotten unregistered in the 249 // meantime 250 it->second(*this); // Do the work 251 252 if (m_terminate_request) 253 return Error(); 254 } 255 } 256 return Error(); 257 } 258