summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp')
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp260
1 files changed, 260 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp b/contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp
new file mode 100644
index 0000000..805bcf2
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp
@@ -0,0 +1,260 @@
+//===-- SelectHelper.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+// Enable this special support for Apple builds where we can have unlimited
+// select bounds. We tried switching to poll() and kqueue and we were panicing
+// the kernel, so we have to stick with select for now.
+#define _DARWIN_UNLIMITED_SELECT
+#endif
+
+// C Includes
+#include <errno.h>
+#if defined(_WIN32)
+// Define NOMINMAX to avoid macros that conflict with std::min and std::max
+#define NOMINMAX
+#include <winsock2.h>
+#else
+#include <sys/select.h>
+#endif
+
+// C++ Includes
+#include <algorithm>
+
+// Other libraries and framework includes
+#include "llvm/ADT/SmallVector.h"
+
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/SelectHelper.h"
+
+SelectHelper::SelectHelper()
+ : m_fd_map(), m_end_time() // Infinite timeout unless
+ // SelectHelper::SetTimeout() gets called
+{}
+
+void SelectHelper::SetTimeout(const std::chrono::microseconds &timeout) {
+ using namespace std::chrono;
+ m_end_time = steady_clock::time_point(steady_clock::now() + timeout);
+}
+
+void SelectHelper::FDSetRead(lldb::socket_t fd) {
+ m_fd_map[fd].read_set = true;
+}
+
+void SelectHelper::FDSetWrite(lldb::socket_t fd) {
+ m_fd_map[fd].write_set = true;
+}
+
+void SelectHelper::FDSetError(lldb::socket_t fd) {
+ m_fd_map[fd].error_set = true;
+}
+
+bool SelectHelper::FDIsSetRead(lldb::socket_t fd) const {
+ auto pos = m_fd_map.find(fd);
+ if (pos != m_fd_map.end())
+ return pos->second.read_is_set;
+ else
+ return false;
+}
+
+bool SelectHelper::FDIsSetWrite(lldb::socket_t fd) const {
+ auto pos = m_fd_map.find(fd);
+ if (pos != m_fd_map.end())
+ return pos->second.write_is_set;
+ else
+ return false;
+}
+
+bool SelectHelper::FDIsSetError(lldb::socket_t fd) const {
+ auto pos = m_fd_map.find(fd);
+ if (pos != m_fd_map.end())
+ return pos->second.error_is_set;
+ else
+ return false;
+}
+
+static void updateMaxFd(llvm::Optional<lldb::socket_t> &vold,
+ lldb::socket_t vnew) {
+ if (!vold.hasValue())
+ vold = vnew;
+ else
+ vold = std::max(*vold, vnew);
+}
+
+lldb_private::Error SelectHelper::Select() {
+ lldb_private::Error error;
+#ifdef _MSC_VER
+ // On windows FD_SETSIZE limits the number of file descriptors, not their
+ // numeric value.
+ lldbassert(m_fd_map.size() <= FD_SETSIZE);
+ if (m_fd_map.size() > FD_SETSIZE)
+ return lldb_private::Error("Too many file descriptors for select()");
+#endif
+
+ llvm::Optional<lldb::socket_t> max_read_fd;
+ llvm::Optional<lldb::socket_t> max_write_fd;
+ llvm::Optional<lldb::socket_t> max_error_fd;
+ llvm::Optional<lldb::socket_t> max_fd;
+ for (auto &pair : m_fd_map) {
+ pair.second.PrepareForSelect();
+ const lldb::socket_t fd = pair.first;
+#if !defined(__APPLE__) && !defined(_MSC_VER)
+ lldbassert(fd < FD_SETSIZE);
+ if (fd >= FD_SETSIZE) {
+ error.SetErrorStringWithFormat("%i is too large for select()", fd);
+ return error;
+ }
+#endif
+ if (pair.second.read_set)
+ updateMaxFd(max_read_fd, fd);
+ if (pair.second.write_set)
+ updateMaxFd(max_write_fd, fd);
+ if (pair.second.error_set)
+ updateMaxFd(max_error_fd, fd);
+ updateMaxFd(max_fd, fd);
+ }
+
+ if (!max_fd.hasValue()) {
+ error.SetErrorString("no valid file descriptors");
+ return error;
+ }
+
+ const unsigned nfds = static_cast<unsigned>(*max_fd) + 1;
+ fd_set *read_fdset_ptr = nullptr;
+ fd_set *write_fdset_ptr = nullptr;
+ fd_set *error_fdset_ptr = nullptr;
+//----------------------------------------------------------------------
+// Initialize and zero out the fdsets
+//----------------------------------------------------------------------
+#if defined(__APPLE__)
+ llvm::SmallVector<fd_set, 1> read_fdset;
+ llvm::SmallVector<fd_set, 1> write_fdset;
+ llvm::SmallVector<fd_set, 1> error_fdset;
+
+ if (max_read_fd.hasValue()) {
+ read_fdset.resize((nfds / FD_SETSIZE) + 1);
+ read_fdset_ptr = read_fdset.data();
+ }
+ if (max_write_fd.hasValue()) {
+ write_fdset.resize((nfds / FD_SETSIZE) + 1);
+ write_fdset_ptr = write_fdset.data();
+ }
+ if (max_error_fd.hasValue()) {
+ error_fdset.resize((nfds / FD_SETSIZE) + 1);
+ error_fdset_ptr = error_fdset.data();
+ }
+ for (auto &fd_set : read_fdset)
+ FD_ZERO(&fd_set);
+ for (auto &fd_set : write_fdset)
+ FD_ZERO(&fd_set);
+ for (auto &fd_set : error_fdset)
+ FD_ZERO(&fd_set);
+#else
+ fd_set read_fdset;
+ fd_set write_fdset;
+ fd_set error_fdset;
+
+ if (max_read_fd.hasValue()) {
+ FD_ZERO(&read_fdset);
+ read_fdset_ptr = &read_fdset;
+ }
+ if (max_write_fd.hasValue()) {
+ FD_ZERO(&write_fdset);
+ write_fdset_ptr = &write_fdset;
+ }
+ if (max_error_fd.hasValue()) {
+ FD_ZERO(&error_fdset);
+ error_fdset_ptr = &error_fdset;
+ }
+#endif
+ //----------------------------------------------------------------------
+ // Set the FD bits in the fdsets for read/write/error
+ //----------------------------------------------------------------------
+ for (auto &pair : m_fd_map) {
+ const lldb::socket_t fd = pair.first;
+
+ if (pair.second.read_set)
+ FD_SET(fd, read_fdset_ptr);
+
+ if (pair.second.write_set)
+ FD_SET(fd, write_fdset_ptr);
+
+ if (pair.second.error_set)
+ FD_SET(fd, error_fdset_ptr);
+ }
+
+ //----------------------------------------------------------------------
+ // Setup our timeout time value if needed
+ //----------------------------------------------------------------------
+ struct timeval *tv_ptr = nullptr;
+ struct timeval tv = {0, 0};
+
+ while (1) {
+ using namespace std::chrono;
+ //------------------------------------------------------------------
+ // Setup out relative timeout based on the end time if we have one
+ //------------------------------------------------------------------
+ if (m_end_time.hasValue()) {
+ tv_ptr = &tv;
+ const auto remaining_dur = duration_cast<microseconds>(
+ m_end_time.getValue() - steady_clock::now());
+ if (remaining_dur.count() > 0) {
+ // Wait for a specific amount of time
+ const auto dur_secs = duration_cast<seconds>(remaining_dur);
+ const auto dur_usecs = remaining_dur % seconds(1);
+ tv.tv_sec = dur_secs.count();
+ tv.tv_usec = dur_usecs.count();
+ } else {
+ // Just poll once with no timeout
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ }
+ }
+ const int num_set_fds = ::select(nfds, read_fdset_ptr, write_fdset_ptr,
+ error_fdset_ptr, tv_ptr);
+ if (num_set_fds < 0) {
+ // We got an error
+ error.SetErrorToErrno();
+ if (error.GetError() == EINTR) {
+ error.Clear();
+ continue; // Keep calling select if we get EINTR
+ } else
+ return error;
+ } else if (num_set_fds == 0) {
+ // Timeout
+ error.SetError(ETIMEDOUT, lldb::eErrorTypePOSIX);
+ error.SetErrorString("timed out");
+ return error;
+ } else {
+ // One or more descriptors were set, update the FDInfo::select_is_set mask
+ // so users can ask the SelectHelper class so clients can call one of:
+
+ for (auto &pair : m_fd_map) {
+ const int fd = pair.first;
+
+ if (pair.second.read_set) {
+ if (FD_ISSET(fd, read_fdset_ptr))
+ pair.second.read_is_set = true;
+ }
+ if (pair.second.write_set) {
+ if (FD_ISSET(fd, write_fdset_ptr))
+ pair.second.write_is_set = true;
+ }
+ if (pair.second.error_set) {
+ if (FD_ISSET(fd, error_fdset_ptr))
+ pair.second.error_is_set = true;
+ }
+ }
+ break;
+ }
+ }
+ return error;
+}
OpenPOWER on IntegriCloud