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