1ee1f578dSGreg Clayton //===-- SelectHelper.cpp ----------------------------------------*- C++ -*-===// 2ee1f578dSGreg Clayton // 3ee1f578dSGreg Clayton // The LLVM Compiler Infrastructure 4ee1f578dSGreg Clayton // 5ee1f578dSGreg Clayton // This file is distributed under the University of Illinois Open Source 6ee1f578dSGreg Clayton // License. See LICENSE.TXT for details. 7ee1f578dSGreg Clayton // 8ee1f578dSGreg Clayton //===----------------------------------------------------------------------===// 9ee1f578dSGreg Clayton 10ee1f578dSGreg Clayton #if defined(__APPLE__) 11ee1f578dSGreg Clayton // Enable this special support for Apple builds where we can have unlimited 12ee1f578dSGreg Clayton // select bounds. We tried switching to poll() and kqueue and we were panicing 13ee1f578dSGreg Clayton // the kernel, so we have to stick with select for now. 14ee1f578dSGreg Clayton #define _DARWIN_UNLIMITED_SELECT 15ee1f578dSGreg Clayton #endif 16ee1f578dSGreg Clayton 17ee1f578dSGreg Clayton // C Includes 18ee1f578dSGreg Clayton #include <errno.h> 19ee1f578dSGreg Clayton #if defined(_WIN32) 20ee1f578dSGreg Clayton // Define NOMINMAX to avoid macros that conflict with std::min and std::max 21ee1f578dSGreg Clayton #define NOMINMAX 22ee1f578dSGreg Clayton #include <winsock2.h> 23ee1f578dSGreg Clayton #else 24ee1f578dSGreg Clayton #include <sys/select.h> 25ee1f578dSGreg Clayton #endif 26ee1f578dSGreg Clayton 27ee1f578dSGreg Clayton // C++ Includes 28ee1f578dSGreg Clayton #include <algorithm> 29ee1f578dSGreg Clayton 30ee1f578dSGreg Clayton // Other libraries and framework includes 31ee1f578dSGreg Clayton #include "llvm/ADT/SmallVector.h" 32ee1f578dSGreg Clayton 33ee1f578dSGreg Clayton // Project includes 34ee1f578dSGreg Clayton #include "lldb/Core/Error.h" 35ee1f578dSGreg Clayton #include "lldb/Utility/SelectHelper.h" 36ee1f578dSGreg Clayton #include "lldb/Utility/LLDBAssert.h" 37ee1f578dSGreg Clayton 38ee1f578dSGreg Clayton SelectHelper::SelectHelper() : 39ee1f578dSGreg Clayton m_fd_map(), 40ee1f578dSGreg Clayton m_end_time() // Infinite timeout unless SelectHelper::SetTimeout() gets called 41ee1f578dSGreg Clayton { 42ee1f578dSGreg Clayton } 43ee1f578dSGreg Clayton 44ee1f578dSGreg Clayton void 45ee1f578dSGreg Clayton SelectHelper::SetTimeout(const std::chrono::microseconds &timeout) 46ee1f578dSGreg Clayton { 47ee1f578dSGreg Clayton using namespace std::chrono; 48ee1f578dSGreg Clayton m_end_time = steady_clock::time_point(steady_clock::now() + timeout); 49ee1f578dSGreg Clayton } 50ee1f578dSGreg Clayton 51ee1f578dSGreg Clayton void 52ee1f578dSGreg Clayton SelectHelper::FDSetRead(int fd) 53ee1f578dSGreg Clayton { 54ee1f578dSGreg Clayton m_fd_map[fd].read_set = true; 55ee1f578dSGreg Clayton } 56ee1f578dSGreg Clayton 57ee1f578dSGreg Clayton void 58ee1f578dSGreg Clayton SelectHelper::FDSetWrite(int fd) 59ee1f578dSGreg Clayton { 60ee1f578dSGreg Clayton m_fd_map[fd].write_set = true; 61ee1f578dSGreg Clayton } 62ee1f578dSGreg Clayton 63ee1f578dSGreg Clayton void 64ee1f578dSGreg Clayton SelectHelper::FDSetError(int fd) 65ee1f578dSGreg Clayton { 66ee1f578dSGreg Clayton m_fd_map[fd].error_set = true; 67ee1f578dSGreg Clayton } 68ee1f578dSGreg Clayton 69ee1f578dSGreg Clayton bool 70ee1f578dSGreg Clayton SelectHelper::FDIsSetRead(int fd) const 71ee1f578dSGreg Clayton { 72ee1f578dSGreg Clayton auto pos = m_fd_map.find(fd); 73ee1f578dSGreg Clayton if (pos != m_fd_map.end()) 74ee1f578dSGreg Clayton return pos->second.read_is_set; 75ee1f578dSGreg Clayton else 76ee1f578dSGreg Clayton return false; 77ee1f578dSGreg Clayton } 78ee1f578dSGreg Clayton 79ee1f578dSGreg Clayton bool 80ee1f578dSGreg Clayton SelectHelper::FDIsSetWrite(int fd) const 81ee1f578dSGreg Clayton { 82ee1f578dSGreg Clayton auto pos = m_fd_map.find(fd); 83ee1f578dSGreg Clayton if (pos != m_fd_map.end()) 84ee1f578dSGreg Clayton return pos->second.write_is_set; 85ee1f578dSGreg Clayton else 86ee1f578dSGreg Clayton return false; 87ee1f578dSGreg Clayton } 88ee1f578dSGreg Clayton 89ee1f578dSGreg Clayton bool 90ee1f578dSGreg Clayton SelectHelper::FDIsSetError(int fd) const 91ee1f578dSGreg Clayton { 92ee1f578dSGreg Clayton auto pos = m_fd_map.find(fd); 93ee1f578dSGreg Clayton if (pos != m_fd_map.end()) 94ee1f578dSGreg Clayton return pos->second.error_is_set; 95ee1f578dSGreg Clayton else 96ee1f578dSGreg Clayton return false; 97ee1f578dSGreg Clayton } 98ee1f578dSGreg Clayton 99ee1f578dSGreg Clayton lldb_private::Error 100ee1f578dSGreg Clayton SelectHelper::Select() 101ee1f578dSGreg Clayton { 102ee1f578dSGreg Clayton lldb_private::Error error; 103*fdb2d99eSPavel Labath #ifdef _MSC_VER 104*fdb2d99eSPavel Labath // On windows FD_SETSIZE limits the number of file descriptors, not their numeric value. 105*fdb2d99eSPavel Labath lldbassert(m_fd_map.size() <= FD_SETSIZE); 106*fdb2d99eSPavel Labath if (m_fd_map.size() > FD_SETSIZE) 107*fdb2d99eSPavel Labath return lldb_private::Error("Too many file descriptors for select()"); 108*fdb2d99eSPavel Labath #endif 109ee1f578dSGreg Clayton 110ee1f578dSGreg Clayton int max_read_fd = -1; 111ee1f578dSGreg Clayton int max_write_fd = -1; 112ee1f578dSGreg Clayton int max_error_fd = -1; 113ee1f578dSGreg Clayton int max_fd = -1; 114ee1f578dSGreg Clayton for (auto &pair : m_fd_map) 115ee1f578dSGreg Clayton { 116ee1f578dSGreg Clayton pair.second.PrepareForSelect(); 117ee1f578dSGreg Clayton const int fd = pair.first; 118*fdb2d99eSPavel Labath #if !defined(__APPLE__) && !defined(_MSC_VER) 119ee1f578dSGreg Clayton lldbassert(fd < FD_SETSIZE); 120ee1f578dSGreg Clayton if (fd >= FD_SETSIZE) 121ee1f578dSGreg Clayton { 122ee1f578dSGreg Clayton error.SetErrorStringWithFormat("%i is too large for select()", fd); 123ee1f578dSGreg Clayton return error; 124ee1f578dSGreg Clayton } 125ee1f578dSGreg Clayton #endif 126ee1f578dSGreg Clayton if (pair.second.read_set) 127ee1f578dSGreg Clayton { 128ee1f578dSGreg Clayton max_read_fd = std::max<int>(fd, max_read_fd); 129ee1f578dSGreg Clayton max_fd = std::max<int>(fd, max_fd); 130ee1f578dSGreg Clayton } 131ee1f578dSGreg Clayton if (pair.second.write_set) 132ee1f578dSGreg Clayton { 133ee1f578dSGreg Clayton max_write_fd = std::max<int>(fd, max_write_fd); 134ee1f578dSGreg Clayton max_fd = std::max<int>(fd, max_fd); 135ee1f578dSGreg Clayton } 136ee1f578dSGreg Clayton if (pair.second.error_set) 137ee1f578dSGreg Clayton { 138ee1f578dSGreg Clayton max_error_fd = std::max<int>(fd, max_error_fd); 139ee1f578dSGreg Clayton max_fd = std::max<int>(fd, max_fd); 140ee1f578dSGreg Clayton } 141ee1f578dSGreg Clayton } 142ee1f578dSGreg Clayton 143ee1f578dSGreg Clayton if (max_fd == -1) 144ee1f578dSGreg Clayton { 145ee1f578dSGreg Clayton error.SetErrorString("no valid file descriptors"); 146ee1f578dSGreg Clayton return error; 147ee1f578dSGreg Clayton } 148ee1f578dSGreg Clayton 149ee1f578dSGreg Clayton const int nfds = max_fd + 1; 150ee1f578dSGreg Clayton fd_set *read_fdset_ptr = nullptr; 151ee1f578dSGreg Clayton fd_set *write_fdset_ptr = nullptr; 152ee1f578dSGreg Clayton fd_set *error_fdset_ptr = nullptr; 153ee1f578dSGreg Clayton //---------------------------------------------------------------------- 154ee1f578dSGreg Clayton // Initialize and zero out the fdsets 155ee1f578dSGreg Clayton //---------------------------------------------------------------------- 156ee1f578dSGreg Clayton #if defined(__APPLE__) 157ee1f578dSGreg Clayton llvm::SmallVector<fd_set, 1> read_fdset; 158ee1f578dSGreg Clayton llvm::SmallVector<fd_set, 1> write_fdset; 159ee1f578dSGreg Clayton llvm::SmallVector<fd_set, 1> error_fdset; 160ee1f578dSGreg Clayton 161ee1f578dSGreg Clayton if (max_read_fd >= 0) 162ee1f578dSGreg Clayton { 163ee1f578dSGreg Clayton read_fdset.resize((nfds / FD_SETSIZE) + 1); 164ee1f578dSGreg Clayton read_fdset_ptr = read_fdset.data(); 165ee1f578dSGreg Clayton } 166ee1f578dSGreg Clayton if (max_write_fd >= 0) 167ee1f578dSGreg Clayton { 168ee1f578dSGreg Clayton write_fdset.resize((nfds / FD_SETSIZE) + 1); 169ee1f578dSGreg Clayton write_fdset_ptr = write_fdset.data(); 170ee1f578dSGreg Clayton } 171ee1f578dSGreg Clayton if (max_error_fd >= 0) 172ee1f578dSGreg Clayton { 173ee1f578dSGreg Clayton error_fdset.resize((nfds / FD_SETSIZE) + 1); 174ee1f578dSGreg Clayton error_fdset_ptr = error_fdset.data(); 175ee1f578dSGreg Clayton } 176ee1f578dSGreg Clayton for (auto &fd_set : read_fdset) 177ee1f578dSGreg Clayton FD_ZERO(&fd_set); 178ee1f578dSGreg Clayton for (auto &fd_set : write_fdset) 179ee1f578dSGreg Clayton FD_ZERO(&fd_set); 180ee1f578dSGreg Clayton for (auto &fd_set : error_fdset) 181ee1f578dSGreg Clayton FD_ZERO(&fd_set); 182ee1f578dSGreg Clayton #else 183ee1f578dSGreg Clayton fd_set read_fdset; 184ee1f578dSGreg Clayton fd_set write_fdset; 185ee1f578dSGreg Clayton fd_set error_fdset; 186ee1f578dSGreg Clayton 187ee1f578dSGreg Clayton if (max_read_fd >= 0) 188ee1f578dSGreg Clayton { 189ee1f578dSGreg Clayton FD_ZERO(&read_fdset); 190ee1f578dSGreg Clayton read_fdset_ptr = &read_fdset; 191ee1f578dSGreg Clayton } 192ee1f578dSGreg Clayton if (max_write_fd >= 0) 193ee1f578dSGreg Clayton { 194ee1f578dSGreg Clayton FD_ZERO(&write_fdset); 195ee1f578dSGreg Clayton write_fdset_ptr = &write_fdset; 196ee1f578dSGreg Clayton } 197ee1f578dSGreg Clayton if (max_error_fd >= 0) 198ee1f578dSGreg Clayton { 199ee1f578dSGreg Clayton FD_ZERO(&error_fdset); 200ee1f578dSGreg Clayton error_fdset_ptr = &error_fdset; 201ee1f578dSGreg Clayton } 202ee1f578dSGreg Clayton #endif 203ee1f578dSGreg Clayton //---------------------------------------------------------------------- 204ee1f578dSGreg Clayton // Set the FD bits in the fdsets for read/write/error 205ee1f578dSGreg Clayton //---------------------------------------------------------------------- 206ee1f578dSGreg Clayton for (auto &pair : m_fd_map) 207ee1f578dSGreg Clayton { 208ee1f578dSGreg Clayton const int fd = pair.first; 209ee1f578dSGreg Clayton 210ee1f578dSGreg Clayton if (pair.second.read_set) 211ee1f578dSGreg Clayton FD_SET(fd, read_fdset_ptr); 212ee1f578dSGreg Clayton 213ee1f578dSGreg Clayton if (pair.second.write_set) 214ee1f578dSGreg Clayton FD_SET(fd, write_fdset_ptr); 215ee1f578dSGreg Clayton 216ee1f578dSGreg Clayton if (pair.second.error_set) 217ee1f578dSGreg Clayton FD_SET(fd, error_fdset_ptr); 218ee1f578dSGreg Clayton } 219ee1f578dSGreg Clayton 220ee1f578dSGreg Clayton //---------------------------------------------------------------------- 221ee1f578dSGreg Clayton // Setup our timeout time value if needed 222ee1f578dSGreg Clayton //---------------------------------------------------------------------- 223ee1f578dSGreg Clayton struct timeval *tv_ptr = nullptr; 224ee1f578dSGreg Clayton struct timeval tv = {0, 0}; 225ee1f578dSGreg Clayton 226ee1f578dSGreg Clayton while (1) 227ee1f578dSGreg Clayton { 228ee1f578dSGreg Clayton using namespace std::chrono; 229ee1f578dSGreg Clayton //------------------------------------------------------------------ 230ee1f578dSGreg Clayton // Setup out relative timeout based on the end time if we have one 231ee1f578dSGreg Clayton //------------------------------------------------------------------ 232ee1f578dSGreg Clayton if (m_end_time.hasValue()) 233ee1f578dSGreg Clayton { 234ee1f578dSGreg Clayton tv_ptr = &tv; 235ee1f578dSGreg Clayton const auto remaining_dur = duration_cast<microseconds>(m_end_time.getValue() - steady_clock::now()); 236ee1f578dSGreg Clayton if (remaining_dur.count() > 0) 237ee1f578dSGreg Clayton { 238ee1f578dSGreg Clayton // Wait for a specific amount of time 239ee1f578dSGreg Clayton const auto dur_secs = duration_cast<seconds>(remaining_dur); 240ee1f578dSGreg Clayton const auto dur_usecs = remaining_dur % seconds(1); 241ee1f578dSGreg Clayton tv.tv_sec = dur_secs.count(); 242ee1f578dSGreg Clayton tv.tv_usec = dur_usecs.count(); 243ee1f578dSGreg Clayton } 244ee1f578dSGreg Clayton else 245ee1f578dSGreg Clayton { 246ee1f578dSGreg Clayton // Just poll once with no timeout 247ee1f578dSGreg Clayton tv.tv_sec = 0; 248ee1f578dSGreg Clayton tv.tv_usec = 0; 249ee1f578dSGreg Clayton } 250ee1f578dSGreg Clayton } 251ee1f578dSGreg Clayton const int num_set_fds = ::select(nfds, read_fdset_ptr, write_fdset_ptr, error_fdset_ptr, tv_ptr); 252ee1f578dSGreg Clayton if (num_set_fds < 0) 253ee1f578dSGreg Clayton { 254ee1f578dSGreg Clayton // We got an error 255ee1f578dSGreg Clayton error.SetErrorToErrno(); 256ee1f578dSGreg Clayton if (error.GetError() == EINTR) 257ee1f578dSGreg Clayton { 258ee1f578dSGreg Clayton error.Clear(); 259ee1f578dSGreg Clayton continue; // Keep calling select if we get EINTR 260ee1f578dSGreg Clayton } 261ee1f578dSGreg Clayton else 262ee1f578dSGreg Clayton return error; 263ee1f578dSGreg Clayton } 264ee1f578dSGreg Clayton else if (num_set_fds == 0) 265ee1f578dSGreg Clayton { 266ee1f578dSGreg Clayton // Timeout 267ee1f578dSGreg Clayton error.SetError(ETIMEDOUT, lldb::eErrorTypePOSIX); 268ee1f578dSGreg Clayton error.SetErrorString("timed out"); 269ee1f578dSGreg Clayton return error; 270ee1f578dSGreg Clayton } 271ee1f578dSGreg Clayton else 272ee1f578dSGreg Clayton { 273ee1f578dSGreg Clayton // One or more descriptors were set, update the FDInfo::select_is_set mask 274ee1f578dSGreg Clayton // so users can ask the SelectHelper class so clients can call one of: 275ee1f578dSGreg Clayton 276ee1f578dSGreg Clayton for (auto &pair : m_fd_map) 277ee1f578dSGreg Clayton { 278ee1f578dSGreg Clayton const int fd = pair.first; 279ee1f578dSGreg Clayton 280ee1f578dSGreg Clayton if (pair.second.read_set) 281ee1f578dSGreg Clayton { 282ee1f578dSGreg Clayton if (FD_ISSET(fd, read_fdset_ptr)) 283ee1f578dSGreg Clayton pair.second.read_is_set = true; 284ee1f578dSGreg Clayton } 285ee1f578dSGreg Clayton if (pair.second.write_set) 286ee1f578dSGreg Clayton { 287ee1f578dSGreg Clayton if (FD_ISSET(fd, write_fdset_ptr)) 288ee1f578dSGreg Clayton pair.second.write_is_set = true; 289ee1f578dSGreg Clayton } 290ee1f578dSGreg Clayton if (pair.second.error_set) 291ee1f578dSGreg Clayton { 292ee1f578dSGreg Clayton if (FD_ISSET(fd, error_fdset_ptr)) 293ee1f578dSGreg Clayton pair.second.error_is_set = true; 294ee1f578dSGreg Clayton } 295ee1f578dSGreg Clayton } 296ee1f578dSGreg Clayton break; 297ee1f578dSGreg Clayton } 298ee1f578dSGreg Clayton } 299ee1f578dSGreg Clayton return error; 300ee1f578dSGreg Clayton } 301