SelectHelper.cpp revision 321369
119370Spst//===-- SelectHelper.cpp ----------------------------------------*- C++ -*-===// 298944Sobrien// 398944Sobrien// The LLVM Compiler Infrastructure 419370Spst// 598944Sobrien// This file is distributed under the University of Illinois Open Source 619370Spst// License. See LICENSE.TXT for details. 798944Sobrien// 898944Sobrien//===----------------------------------------------------------------------===// 998944Sobrien 1098944Sobrien#if defined(__APPLE__) 1119370Spst// Enable this special support for Apple builds where we can have unlimited 1298944Sobrien// select bounds. We tried switching to poll() and kqueue and we were panicing 1398944Sobrien// the kernel, so we have to stick with select for now. 1498944Sobrien#define _DARWIN_UNLIMITED_SELECT 1598944Sobrien#endif 1619370Spst 1798944Sobrien#include "lldb/Utility/SelectHelper.h" 1898944Sobrien#include "lldb/Utility/LLDBAssert.h" 1998944Sobrien#include "lldb/Utility/Status.h" 2098944Sobrien#include "lldb/lldb-enumerations.h" // for ErrorType::eErrorTypePOSIX 2119370Spst#include "lldb/lldb-types.h" // for socket_t 2219370Spst 2319370Spst#include "llvm/ADT/DenseMap.h" // for DenseMapPair, DenseMap, Dense... 2419370Spst#include "llvm/ADT/Optional.h" // for Optional 2519370Spst 2619370Spst#include <algorithm> 2719370Spst#include <chrono> // for microseconds, seconds, steady... 2819370Spst 2946283Sdfr#include <errno.h> 3019370Spst#if defined(_WIN32) 3119370Spst// Define NOMINMAX to avoid macros that conflict with std::min and std::max 3219370Spst#define NOMINMAX 3319370Spst#include <winsock2.h> 3498944Sobrien#else 3598944Sobrien#include <sys/select.h> 3619370Spst#endif 3719370Spst 3819370Spst 3919370SpstSelectHelper::SelectHelper() 4019370Spst : m_fd_map(), m_end_time() // Infinite timeout unless 4119370Spst // SelectHelper::SetTimeout() gets called 4246283Sdfr{} 4346283Sdfr 4446283Sdfrvoid SelectHelper::SetTimeout(const std::chrono::microseconds &timeout) { 4546283Sdfr using namespace std::chrono; 4619370Spst m_end_time = steady_clock::time_point(steady_clock::now() + timeout); 4719370Spst} 4819370Spst 4919370Spstvoid SelectHelper::FDSetRead(lldb::socket_t fd) { 5019370Spst m_fd_map[fd].read_set = true; 5119370Spst} 5219370Spst 5319370Spstvoid SelectHelper::FDSetWrite(lldb::socket_t fd) { 5419370Spst m_fd_map[fd].write_set = true; 5598944Sobrien} 5698944Sobrien 5798944Sobrienvoid SelectHelper::FDSetError(lldb::socket_t fd) { 5898944Sobrien m_fd_map[fd].error_set = true; 5946283Sdfr} 6098944Sobrien 6146283Sdfrbool SelectHelper::FDIsSetRead(lldb::socket_t fd) const { 6246283Sdfr auto pos = m_fd_map.find(fd); 6398944Sobrien if (pos != m_fd_map.end()) 6446283Sdfr return pos->second.read_is_set; 6598944Sobrien else 6619370Spst return false; 6798944Sobrien} 6898944Sobrien 6998944Sobrienbool SelectHelper::FDIsSetWrite(lldb::socket_t fd) const { 7019370Spst auto pos = m_fd_map.find(fd); 7119370Spst if (pos != m_fd_map.end()) 7219370Spst return pos->second.write_is_set; 7398944Sobrien else 7419370Spst return false; 7519370Spst} 7619370Spst 7719370Spstbool SelectHelper::FDIsSetError(lldb::socket_t fd) const { 7819370Spst auto pos = m_fd_map.find(fd); 7919370Spst if (pos != m_fd_map.end()) 8019370Spst return pos->second.error_is_set; 8119370Spst else 8219370Spst return false; 8319370Spst} 8419370Spst 8519370Spststatic void updateMaxFd(llvm::Optional<lldb::socket_t> &vold, 8619370Spst lldb::socket_t vnew) { 8719370Spst if (!vold.hasValue()) 8819370Spst vold = vnew; 8919370Spst else 9019370Spst vold = std::max(*vold, vnew); 9119370Spst} 9219370Spst 9319370Spstlldb_private::Status SelectHelper::Select() { 9419370Spst lldb_private::Status error; 9519370Spst#ifdef _MSC_VER 9619370Spst // On windows FD_SETSIZE limits the number of file descriptors, not their 9719370Spst // numeric value. 9819370Spst lldbassert(m_fd_map.size() <= FD_SETSIZE); 9919370Spst if (m_fd_map.size() > FD_SETSIZE) 10046283Sdfr return lldb_private::Status("Too many file descriptors for select()"); 10119370Spst#endif 10219370Spst 10319370Spst llvm::Optional<lldb::socket_t> max_read_fd; 10419370Spst llvm::Optional<lldb::socket_t> max_write_fd; 10519370Spst llvm::Optional<lldb::socket_t> max_error_fd; 10619370Spst llvm::Optional<lldb::socket_t> max_fd; 10719370Spst for (auto &pair : m_fd_map) { 10819370Spst pair.second.PrepareForSelect(); 10919370Spst const lldb::socket_t fd = pair.first; 11019370Spst#if !defined(__APPLE__) && !defined(_MSC_VER) 11119370Spst lldbassert(fd < FD_SETSIZE); 11219370Spst if (fd >= FD_SETSIZE) { 11346283Sdfr error.SetErrorStringWithFormat("%i is too large for select()", fd); 11419370Spst return error; 11598944Sobrien } 11698944Sobrien#endif 11798944Sobrien if (pair.second.read_set) 11898944Sobrien updateMaxFd(max_read_fd, fd); 11998944Sobrien if (pair.second.write_set) 12019370Spst updateMaxFd(max_write_fd, fd); 12119370Spst if (pair.second.error_set) 12219370Spst updateMaxFd(max_error_fd, fd); 12398944Sobrien updateMaxFd(max_fd, fd); 12419370Spst } 12519370Spst 12619370Spst if (!max_fd.hasValue()) { 12719370Spst error.SetErrorString("no valid file descriptors"); 12819370Spst return error; 12919370Spst } 13019370Spst 13119370Spst const unsigned nfds = static_cast<unsigned>(*max_fd) + 1; 13298944Sobrien fd_set *read_fdset_ptr = nullptr; 13398944Sobrien fd_set *write_fdset_ptr = nullptr; 13498944Sobrien fd_set *error_fdset_ptr = nullptr; 13598944Sobrien//---------------------------------------------------------------------- 13619370Spst// Initialize and zero out the fdsets 13719370Spst//---------------------------------------------------------------------- 13819370Spst#if defined(__APPLE__) 13919370Spst llvm::SmallVector<fd_set, 1> read_fdset; 14019370Spst llvm::SmallVector<fd_set, 1> write_fdset; 14119370Spst llvm::SmallVector<fd_set, 1> error_fdset; 14298944Sobrien 14319370Spst if (max_read_fd.hasValue()) { 14419370Spst read_fdset.resize((nfds / FD_SETSIZE) + 1); 14598944Sobrien read_fdset_ptr = read_fdset.data(); 14619370Spst } 14719370Spst if (max_write_fd.hasValue()) { 14819370Spst write_fdset.resize((nfds / FD_SETSIZE) + 1); 14919370Spst write_fdset_ptr = write_fdset.data(); 15019370Spst } 15119370Spst if (max_error_fd.hasValue()) { 15219370Spst error_fdset.resize((nfds / FD_SETSIZE) + 1); 15346283Sdfr error_fdset_ptr = error_fdset.data(); 15446283Sdfr } 15546283Sdfr for (auto &fd_set : read_fdset) 15619370Spst FD_ZERO(&fd_set); 15719370Spst for (auto &fd_set : write_fdset) 15819370Spst FD_ZERO(&fd_set); 15919370Spst for (auto &fd_set : error_fdset) 16019370Spst FD_ZERO(&fd_set); 16119370Spst#else 16219370Spst fd_set read_fdset; 16319370Spst fd_set write_fdset; 16419370Spst fd_set error_fdset; 16519370Spst 16619370Spst if (max_read_fd.hasValue()) { 16719370Spst FD_ZERO(&read_fdset); 16819370Spst read_fdset_ptr = &read_fdset; 16919370Spst } 17019370Spst if (max_write_fd.hasValue()) { 17119370Spst FD_ZERO(&write_fdset); 17219370Spst write_fdset_ptr = &write_fdset; 17319370Spst } 17419370Spst if (max_error_fd.hasValue()) { 17519370Spst FD_ZERO(&error_fdset); 17698944Sobrien error_fdset_ptr = &error_fdset; 17719370Spst } 17819370Spst#endif 17919370Spst //---------------------------------------------------------------------- 18019370Spst // Set the FD bits in the fdsets for read/write/error 18119370Spst //---------------------------------------------------------------------- 18298944Sobrien for (auto &pair : m_fd_map) { 18319370Spst const lldb::socket_t fd = pair.first; 18419370Spst 18519370Spst if (pair.second.read_set) 18698944Sobrien FD_SET(fd, read_fdset_ptr); 18798944Sobrien 18819370Spst if (pair.second.write_set) 18998944Sobrien FD_SET(fd, write_fdset_ptr); 19098944Sobrien 19146283Sdfr if (pair.second.error_set) 19219370Spst FD_SET(fd, error_fdset_ptr); 19346283Sdfr } 19419370Spst 19519370Spst //---------------------------------------------------------------------- 19619370Spst // Setup our timeout time value if needed 19798944Sobrien //---------------------------------------------------------------------- 19898944Sobrien struct timeval *tv_ptr = nullptr; 19919370Spst struct timeval tv = {0, 0}; 20019370Spst 20119370Spst while (1) { 20219370Spst using namespace std::chrono; 20346283Sdfr //------------------------------------------------------------------ 20498944Sobrien // Setup out relative timeout based on the end time if we have one 20546283Sdfr //------------------------------------------------------------------ 20646283Sdfr if (m_end_time.hasValue()) { 20746283Sdfr tv_ptr = &tv; 20846283Sdfr const auto remaining_dur = duration_cast<microseconds>( 20946283Sdfr m_end_time.getValue() - steady_clock::now()); 21046283Sdfr if (remaining_dur.count() > 0) { 21198944Sobrien // Wait for a specific amount of time 21246283Sdfr const auto dur_secs = duration_cast<seconds>(remaining_dur); 21398944Sobrien const auto dur_usecs = remaining_dur % seconds(1); 21446283Sdfr tv.tv_sec = dur_secs.count(); 21546283Sdfr tv.tv_usec = dur_usecs.count(); 21646283Sdfr } else { 21719370Spst // Just poll once with no timeout 21819370Spst tv.tv_sec = 0; 21919370Spst tv.tv_usec = 0; 22019370Spst } 22198944Sobrien } 22219370Spst const int num_set_fds = ::select(nfds, read_fdset_ptr, write_fdset_ptr, 22319370Spst error_fdset_ptr, tv_ptr); 22419370Spst if (num_set_fds < 0) { 22519370Spst // We got an error 22619370Spst error.SetErrorToErrno(); 22719370Spst if (error.GetError() == EINTR) { 22819370Spst error.Clear(); 22919370Spst continue; // Keep calling select if we get EINTR 23098944Sobrien } else 23198944Sobrien return error; 23219370Spst } else if (num_set_fds == 0) { 23319370Spst // Timeout 23419370Spst error.SetError(ETIMEDOUT, lldb::eErrorTypePOSIX); 23519370Spst error.SetErrorString("timed out"); 23619370Spst return error; 23719370Spst } else { 23898944Sobrien // One or more descriptors were set, update the FDInfo::select_is_set mask 23998944Sobrien // so users can ask the SelectHelper class so clients can call one of: 24098944Sobrien 24119370Spst for (auto &pair : m_fd_map) { 24219370Spst const int fd = pair.first; 24319370Spst 24419370Spst if (pair.second.read_set) { 24598944Sobrien if (FD_ISSET(fd, read_fdset_ptr)) 24646283Sdfr pair.second.read_is_set = true; 24798944Sobrien } 24846283Sdfr if (pair.second.write_set) { 24919370Spst if (FD_ISSET(fd, write_fdset_ptr)) 25019370Spst pair.second.write_is_set = true; 25119370Spst } 25298944Sobrien if (pair.second.error_set) { 25398944Sobrien if (FD_ISSET(fd, error_fdset_ptr)) 25498944Sobrien pair.second.error_is_set = true; 25598944Sobrien } 25698944Sobrien } 25798944Sobrien break; 25898944Sobrien } 25998944Sobrien } 26098944Sobrien return error; 26198944Sobrien} 26219370Spst