summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/lldb/source/Utility/SelectHelper.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 14:33:06 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 14:33:06 +0000
commit061da546b983eb767bad15e67af1174fb0bcf31c (patch)
tree83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/source/Utility/SelectHelper.cpp
parentImport LLVM 10.0.0 release including clang, lld and lldb. (diff)
downloadwireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz
wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/source/Utility/SelectHelper.cpp')
-rw-r--r--gnu/llvm/lldb/source/Utility/SelectHelper.cpp254
1 files changed, 254 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/source/Utility/SelectHelper.cpp b/gnu/llvm/lldb/source/Utility/SelectHelper.cpp
new file mode 100644
index 00000000000..9f5ca586e1e
--- /dev/null
+++ b/gnu/llvm/lldb/source/Utility/SelectHelper.cpp
@@ -0,0 +1,254 @@
+//===-- SelectHelper.cpp ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#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
+
+#include "lldb/Utility/SelectHelper.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-types.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
+
+#include <algorithm>
+#include <chrono>
+
+#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/time.h>
+#include <sys/select.h>
+#endif
+
+
+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::Status SelectHelper::Select() {
+ lldb_private::Status error;
+#ifdef _WIN32
+ // 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::Status("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(_WIN32)
+ lldbassert(fd < static_cast<int>(FD_SETSIZE));
+ if (fd >= static_cast<int>(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 (true) {
+ 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;
+}