blob: 40c85bee60728a1a3f7d608fe2a3387804b77de7 [file] [log] [blame]
Raphael Isemann80814282020-01-24 07:23:271//===-- SelectHelper.cpp --------------------------------------------------===//
Greg Claytonee1f5782016-08-10 22:43:482//
Chandler Carruth2946cd72019-01-19 08:50:563// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Greg Claytonee1f5782016-08-10 22:43:486//
7//===----------------------------------------------------------------------===//
8
9#if defined(__APPLE__)
10// Enable this special support for Apple builds where we can have unlimited
11// select bounds. We tried switching to poll() and kqueue and we were panicing
12// the kernel, so we have to stick with select for now.
13#define _DARWIN_UNLIMITED_SELECT
14#endif
15
Zachary Turner4479ac12017-04-06 18:12:2416#include "lldb/Utility/SelectHelper.h"
Zachary Turner4479ac12017-04-06 18:12:2417#include "lldb/Utility/LLDBAssert.h"
Zachary Turner97206d52017-05-12 04:51:5518#include "lldb/Utility/Status.h"
Jonas Devlieghere672d2c12018-11-11 23:16:4319#include "lldb/lldb-enumerations.h"
20#include "lldb/lldb-types.h"
Zachary Turner4479ac12017-04-06 18:12:2421
Jonas Devlieghere672d2c12018-11-11 23:16:4322#include "llvm/ADT/DenseMap.h"
23#include "llvm/ADT/Optional.h"
Zachary Turner4479ac12017-04-06 18:12:2424
25#include <algorithm>
Jonas Devlieghere672d2c12018-11-11 23:16:4326#include <chrono>
Zachary Turner4479ac12017-04-06 18:12:2427
Greg Claytonee1f5782016-08-10 22:43:4828#include <errno.h>
29#if defined(_WIN32)
30// Define NOMINMAX to avoid macros that conflict with std::min and std::max
31#define NOMINMAX
32#include <winsock2.h>
33#else
Vedant Kumarc8e1c092017-12-12 20:19:4034#include <sys/time.h>
Greg Claytonee1f5782016-08-10 22:43:4835#include <sys/select.h>
36#endif
37
Greg Claytonee1f5782016-08-10 22:43:4838
Kate Stoneb9c1b512016-09-06 20:57:5039SelectHelper::SelectHelper()
40 : m_fd_map(), m_end_time() // Infinite timeout unless
41 // SelectHelper::SetTimeout() gets called
42{}
43
44void SelectHelper::SetTimeout(const std::chrono::microseconds &timeout) {
45 using namespace std::chrono;
46 m_end_time = steady_clock::time_point(steady_clock::now() + timeout);
Greg Claytonee1f5782016-08-10 22:43:4847}
48
Zachary Turner5a8ad4592016-10-05 17:07:3449void SelectHelper::FDSetRead(lldb::socket_t fd) {
50 m_fd_map[fd].read_set = true;
51}
Kate Stoneb9c1b512016-09-06 20:57:5052
Zachary Turner5a8ad4592016-10-05 17:07:3453void SelectHelper::FDSetWrite(lldb::socket_t fd) {
54 m_fd_map[fd].write_set = true;
55}
Kate Stoneb9c1b512016-09-06 20:57:5056
Zachary Turner5a8ad4592016-10-05 17:07:3457void SelectHelper::FDSetError(lldb::socket_t fd) {
58 m_fd_map[fd].error_set = true;
59}
Kate Stoneb9c1b512016-09-06 20:57:5060
Zachary Turner5a8ad4592016-10-05 17:07:3461bool SelectHelper::FDIsSetRead(lldb::socket_t fd) const {
Kate Stoneb9c1b512016-09-06 20:57:5062 auto pos = m_fd_map.find(fd);
63 if (pos != m_fd_map.end())
64 return pos->second.read_is_set;
65 else
66 return false;
Greg Claytonee1f5782016-08-10 22:43:4867}
68
Zachary Turner5a8ad4592016-10-05 17:07:3469bool SelectHelper::FDIsSetWrite(lldb::socket_t fd) const {
Kate Stoneb9c1b512016-09-06 20:57:5070 auto pos = m_fd_map.find(fd);
71 if (pos != m_fd_map.end())
72 return pos->second.write_is_set;
73 else
74 return false;
Greg Claytonee1f5782016-08-10 22:43:4875}
76
Zachary Turner5a8ad4592016-10-05 17:07:3477bool SelectHelper::FDIsSetError(lldb::socket_t fd) const {
Kate Stoneb9c1b512016-09-06 20:57:5078 auto pos = m_fd_map.find(fd);
79 if (pos != m_fd_map.end())
80 return pos->second.error_is_set;
81 else
82 return false;
Greg Claytonee1f5782016-08-10 22:43:4883}
84
Zachary Turner5a8ad4592016-10-05 17:07:3485static void updateMaxFd(llvm::Optional<lldb::socket_t> &vold,
86 lldb::socket_t vnew) {
87 if (!vold.hasValue())
88 vold = vnew;
89 else
90 vold = std::max(*vold, vnew);
91}
92
Zachary Turner97206d52017-05-12 04:51:5593lldb_private::Status SelectHelper::Select() {
94 lldb_private::Status error;
Martin Storsjo8b98f122019-09-23 12:03:5695#ifdef _WIN32
Kate Stoneb9c1b512016-09-06 20:57:5096 // On windows FD_SETSIZE limits the number of file descriptors, not their
97 // numeric value.
98 lldbassert(m_fd_map.size() <= FD_SETSIZE);
99 if (m_fd_map.size() > FD_SETSIZE)
Zachary Turner97206d52017-05-12 04:51:55100 return lldb_private::Status("Too many file descriptors for select()");
Pavel Labathfdb2d992016-08-12 11:20:21101#endif
Greg Claytonee1f5782016-08-10 22:43:48102
Zachary Turner5a8ad4592016-10-05 17:07:34103 llvm::Optional<lldb::socket_t> max_read_fd;
104 llvm::Optional<lldb::socket_t> max_write_fd;
105 llvm::Optional<lldb::socket_t> max_error_fd;
106 llvm::Optional<lldb::socket_t> max_fd;
Kate Stoneb9c1b512016-09-06 20:57:50107 for (auto &pair : m_fd_map) {
108 pair.second.PrepareForSelect();
Zachary Turner5a8ad4592016-10-05 17:07:34109 const lldb::socket_t fd = pair.first;
Martin Storsjo8b98f122019-09-23 12:03:56110#if !defined(__APPLE__) && !defined(_WIN32)
David Carlier1c79e4e2018-06-25 16:10:20111 lldbassert(fd < static_cast<int>(FD_SETSIZE));
112 if (fd >= static_cast<int>(FD_SETSIZE)) {
Kate Stoneb9c1b512016-09-06 20:57:50113 error.SetErrorStringWithFormat("%i is too large for select()", fd);
114 return error;
115 }
Greg Claytonee1f5782016-08-10 22:43:48116#endif
Zachary Turner5a8ad4592016-10-05 17:07:34117 if (pair.second.read_set)
118 updateMaxFd(max_read_fd, fd);
119 if (pair.second.write_set)
120 updateMaxFd(max_write_fd, fd);
121 if (pair.second.error_set)
122 updateMaxFd(max_error_fd, fd);
123 updateMaxFd(max_fd, fd);
Kate Stoneb9c1b512016-09-06 20:57:50124 }
Greg Claytonee1f5782016-08-10 22:43:48125
Zachary Turner5a8ad4592016-10-05 17:07:34126 if (!max_fd.hasValue()) {
Kate Stoneb9c1b512016-09-06 20:57:50127 error.SetErrorString("no valid file descriptors");
128 return error;
129 }
130
Zachary Turner5a8ad4592016-10-05 17:07:34131 const unsigned nfds = static_cast<unsigned>(*max_fd) + 1;
Kate Stoneb9c1b512016-09-06 20:57:50132 fd_set *read_fdset_ptr = nullptr;
133 fd_set *write_fdset_ptr = nullptr;
134 fd_set *error_fdset_ptr = nullptr;
Kate Stoneb9c1b512016-09-06 20:57:50135// Initialize and zero out the fdsets
Greg Claytonee1f5782016-08-10 22:43:48136#if defined(__APPLE__)
Kate Stoneb9c1b512016-09-06 20:57:50137 llvm::SmallVector<fd_set, 1> read_fdset;
138 llvm::SmallVector<fd_set, 1> write_fdset;
139 llvm::SmallVector<fd_set, 1> error_fdset;
Greg Claytonee1f5782016-08-10 22:43:48140
Zachary Turner5a8ad4592016-10-05 17:07:34141 if (max_read_fd.hasValue()) {
Kate Stoneb9c1b512016-09-06 20:57:50142 read_fdset.resize((nfds / FD_SETSIZE) + 1);
143 read_fdset_ptr = read_fdset.data();
144 }
Zachary Turner5a8ad4592016-10-05 17:07:34145 if (max_write_fd.hasValue()) {
Kate Stoneb9c1b512016-09-06 20:57:50146 write_fdset.resize((nfds / FD_SETSIZE) + 1);
147 write_fdset_ptr = write_fdset.data();
148 }
Zachary Turner5a8ad4592016-10-05 17:07:34149 if (max_error_fd.hasValue()) {
Kate Stoneb9c1b512016-09-06 20:57:50150 error_fdset.resize((nfds / FD_SETSIZE) + 1);
151 error_fdset_ptr = error_fdset.data();
152 }
153 for (auto &fd_set : read_fdset)
154 FD_ZERO(&fd_set);
155 for (auto &fd_set : write_fdset)
156 FD_ZERO(&fd_set);
157 for (auto &fd_set : error_fdset)
158 FD_ZERO(&fd_set);
Greg Claytonee1f5782016-08-10 22:43:48159#else
Kate Stoneb9c1b512016-09-06 20:57:50160 fd_set read_fdset;
161 fd_set write_fdset;
162 fd_set error_fdset;
Greg Claytonee1f5782016-08-10 22:43:48163
Zachary Turner5a8ad4592016-10-05 17:07:34164 if (max_read_fd.hasValue()) {
Kate Stoneb9c1b512016-09-06 20:57:50165 FD_ZERO(&read_fdset);
166 read_fdset_ptr = &read_fdset;
167 }
Zachary Turner5a8ad4592016-10-05 17:07:34168 if (max_write_fd.hasValue()) {
Kate Stoneb9c1b512016-09-06 20:57:50169 FD_ZERO(&write_fdset);
170 write_fdset_ptr = &write_fdset;
171 }
Zachary Turner5a8ad4592016-10-05 17:07:34172 if (max_error_fd.hasValue()) {
Kate Stoneb9c1b512016-09-06 20:57:50173 FD_ZERO(&error_fdset);
174 error_fdset_ptr = &error_fdset;
175 }
Greg Claytonee1f5782016-08-10 22:43:48176#endif
Kate Stoneb9c1b512016-09-06 20:57:50177 // Set the FD bits in the fdsets for read/write/error
Kate Stoneb9c1b512016-09-06 20:57:50178 for (auto &pair : m_fd_map) {
Zachary Turner5a8ad4592016-10-05 17:07:34179 const lldb::socket_t fd = pair.first;
Kate Stoneb9c1b512016-09-06 20:57:50180
181 if (pair.second.read_set)
182 FD_SET(fd, read_fdset_ptr);
183
184 if (pair.second.write_set)
185 FD_SET(fd, write_fdset_ptr);
186
187 if (pair.second.error_set)
188 FD_SET(fd, error_fdset_ptr);
189 }
190
Kate Stoneb9c1b512016-09-06 20:57:50191 // Setup our timeout time value if needed
Kate Stoneb9c1b512016-09-06 20:57:50192 struct timeval *tv_ptr = nullptr;
193 struct timeval tv = {0, 0};
194
Jonas Devlieghere09ad8c82019-05-24 00:44:33195 while (true) {
Kate Stoneb9c1b512016-09-06 20:57:50196 using namespace std::chrono;
Kate Stoneb9c1b512016-09-06 20:57:50197 // Setup out relative timeout based on the end time if we have one
Kate Stoneb9c1b512016-09-06 20:57:50198 if (m_end_time.hasValue()) {
199 tv_ptr = &tv;
200 const auto remaining_dur = duration_cast<microseconds>(
201 m_end_time.getValue() - steady_clock::now());
202 if (remaining_dur.count() > 0) {
203 // Wait for a specific amount of time
204 const auto dur_secs = duration_cast<seconds>(remaining_dur);
205 const auto dur_usecs = remaining_dur % seconds(1);
206 tv.tv_sec = dur_secs.count();
207 tv.tv_usec = dur_usecs.count();
208 } else {
209 // Just poll once with no timeout
210 tv.tv_sec = 0;
211 tv.tv_usec = 0;
212 }
213 }
214 const int num_set_fds = ::select(nfds, read_fdset_ptr, write_fdset_ptr,
215 error_fdset_ptr, tv_ptr);
216 if (num_set_fds < 0) {
217 // We got an error
218 error.SetErrorToErrno();
219 if (error.GetError() == EINTR) {
220 error.Clear();
221 continue; // Keep calling select if we get EINTR
222 } else
223 return error;
224 } else if (num_set_fds == 0) {
225 // Timeout
226 error.SetError(ETIMEDOUT, lldb::eErrorTypePOSIX);
227 error.SetErrorString("timed out");
228 return error;
229 } else {
Adrian Prantl05097242018-04-30 16:49:04230 // One or more descriptors were set, update the FDInfo::select_is_set
231 // mask so users can ask the SelectHelper class so clients can call one
232 // of:
Kate Stoneb9c1b512016-09-06 20:57:50233
234 for (auto &pair : m_fd_map) {
Greg Claytonee1f5782016-08-10 22:43:48235 const int fd = pair.first;
236
Kate Stoneb9c1b512016-09-06 20:57:50237 if (pair.second.read_set) {
238 if (FD_ISSET(fd, read_fdset_ptr))
239 pair.second.read_is_set = true;
240 }
241 if (pair.second.write_set) {
242 if (FD_ISSET(fd, write_fdset_ptr))
243 pair.second.write_is_set = true;
244 }
245 if (pair.second.error_set) {
246 if (FD_ISSET(fd, error_fdset_ptr))
247 pair.second.error_is_set = true;
248 }
249 }
250 break;
Greg Claytonee1f5782016-08-10 22:43:48251 }
Kate Stoneb9c1b512016-09-06 20:57:50252 }
253 return error;
Greg Claytonee1f5782016-08-10 22:43:48254}