1 //===-- MainLoopPosix.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 "lldb/Host/posix/MainLoopPosix.h" 11 12 #include <vector> 13 14 #include "lldb/Core/Error.h" 15 16 using namespace lldb; 17 using namespace lldb_private; 18 19 static sig_atomic_t g_signal_flags[NSIG]; 20 21 static void 22 SignalHandler(int signo, siginfo_t *info, void *) 23 { 24 assert(signo < NSIG); 25 g_signal_flags[signo] = 1; 26 } 27 28 29 MainLoopPosix::~MainLoopPosix() 30 { 31 assert(m_read_fds.size() == 0); 32 assert(m_signals.size() == 0); 33 } 34 35 MainLoopPosix::ReadHandleUP 36 MainLoopPosix::RegisterReadObject(const IOObjectSP &object_sp, const Callback &callback, Error &error) 37 { 38 if (!object_sp || !object_sp->IsValid()) 39 { 40 error.SetErrorString("IO object is not valid."); 41 return nullptr; 42 } 43 44 const bool inserted = m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second; 45 if (! inserted) 46 { 47 error.SetErrorStringWithFormat("File descriptor %d already monitored.", 48 object_sp->GetWaitableHandle()); 49 return nullptr; 50 } 51 52 return CreateReadHandle(object_sp); 53 } 54 55 // We shall block the signal, then install the signal handler. The signal will be unblocked in 56 // the Run() function to check for signal delivery. 57 MainLoopPosix::SignalHandleUP 58 MainLoopPosix::RegisterSignal(int signo, const Callback &callback, Error &error) 59 { 60 if (m_signals.find(signo) != m_signals.end()) 61 { 62 error.SetErrorStringWithFormat("Signal %d already monitored.", signo); 63 return nullptr; 64 } 65 66 SignalInfo info; 67 info.callback = callback; 68 struct sigaction new_action; 69 new_action.sa_sigaction = &SignalHandler; 70 new_action.sa_flags = SA_SIGINFO; 71 sigemptyset(&new_action.sa_mask); 72 sigaddset(&new_action.sa_mask, signo); 73 74 sigset_t old_set; 75 if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set)) 76 { 77 error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n", ret); 78 return nullptr; 79 } 80 81 info.was_blocked = sigismember(&old_set, signo); 82 if (sigaction(signo, &new_action, &info.old_action) == -1) 83 { 84 error.SetErrorToErrno(); 85 if (!info.was_blocked) 86 pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr); 87 return nullptr; 88 } 89 90 m_signals.insert({signo, info}); 91 g_signal_flags[signo] = 0; 92 93 return SignalHandleUP(new SignalHandle(*this, signo)); 94 } 95 96 void 97 MainLoopPosix::UnregisterReadObject(const lldb::IOObjectSP &object_sp) 98 { 99 bool erased = m_read_fds.erase(object_sp->GetWaitableHandle()); 100 (void) erased; 101 assert(erased); 102 } 103 104 void 105 MainLoopPosix::UnregisterSignal(int signo) 106 { 107 // We undo the actions of RegisterSignal on a best-effort basis. 108 auto it = m_signals.find(signo); 109 assert(it != m_signals.end()); 110 111 sigaction(signo, &it->second.old_action, nullptr); 112 113 sigset_t set; 114 sigemptyset(&set); 115 sigaddset(&set, signo); 116 pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set, nullptr); 117 118 m_signals.erase(it); 119 } 120 121 Error 122 MainLoopPosix::Run() 123 { 124 std::vector<int> signals; 125 sigset_t sigmask; 126 std::vector<int> read_fds; 127 fd_set read_fd_set; 128 m_terminate_request = false; 129 130 // run until termination or until we run out of things to listen to 131 while (! m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) 132 { 133 // To avoid problems with callbacks changing the things we're supposed to listen to, we 134 // will store the *real* list of events separately. 135 signals.clear(); 136 read_fds.clear(); 137 FD_ZERO(&read_fd_set); 138 int nfds = 0; 139 140 if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask)) 141 return Error("pthread_sigmask failed with error %d\n", ret); 142 143 for (const auto &fd: m_read_fds) 144 { 145 read_fds.push_back(fd.first); 146 FD_SET(fd.first, &read_fd_set); 147 nfds = std::max(nfds, fd.first+1); 148 } 149 150 for (const auto &sig: m_signals) 151 { 152 signals.push_back(sig.first); 153 sigdelset(&sigmask, sig.first); 154 } 155 156 if (pselect(nfds, &read_fd_set, nullptr, nullptr, nullptr, &sigmask) == -1 && errno != EINTR) 157 return Error(errno, eErrorTypePOSIX); 158 159 for (int sig: signals) 160 { 161 if (g_signal_flags[sig] == 0) 162 continue; // No signal 163 g_signal_flags[sig] = 0; 164 165 auto it = m_signals.find(sig); 166 if (it == m_signals.end()) 167 continue; // Signal must have gotten unregistered in the meantime 168 169 it->second.callback(*this); // Do the work 170 171 if (m_terminate_request) 172 return Error(); 173 } 174 175 for (int fd: read_fds) 176 { 177 if (!FD_ISSET(fd, &read_fd_set)) 178 continue; // Not ready 179 180 auto it = m_read_fds.find(fd); 181 if (it == m_read_fds.end()) 182 continue; // File descriptor must have gotten unregistered in the meantime 183 184 it->second(*this); // Do the work 185 186 if (m_terminate_request) 187 return Error(); 188 } 189 } 190 return Error(); 191 } 192 193 194