]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp
Merge ^/head r317216 through r317280.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Utility / SelectHelper.cpp
1 //===-- SelectHelper.cpp ----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #if defined(__APPLE__)
11 // Enable this special support for Apple builds where we can have unlimited
12 // select bounds. We tried switching to poll() and kqueue and we were panicing
13 // the kernel, so we have to stick with select for now.
14 #define _DARWIN_UNLIMITED_SELECT
15 #endif
16
17 #include "lldb/Utility/SelectHelper.h"
18 #include "lldb/Utility/Error.h"
19 #include "lldb/Utility/LLDBAssert.h"
20 #include "lldb/lldb-enumerations.h" // for ErrorType::eErrorTypePOSIX
21 #include "lldb/lldb-types.h"        // for socket_t
22
23 #include "llvm/ADT/DenseMap.h" // for DenseMapPair, DenseMap, Dense...
24 #include "llvm/ADT/Optional.h" // for Optional
25
26 #include <algorithm>
27 #include <chrono> // for microseconds, seconds, steady...
28
29 #include <errno.h>
30 #if defined(_WIN32)
31 // Define NOMINMAX to avoid macros that conflict with std::min and std::max
32 #define NOMINMAX
33 #include <winsock2.h>
34 #else
35 #include <sys/select.h>
36 #endif
37
38
39 SelectHelper::SelectHelper()
40     : m_fd_map(), m_end_time() // Infinite timeout unless
41                                // SelectHelper::SetTimeout() gets called
42 {}
43
44 void SelectHelper::SetTimeout(const std::chrono::microseconds &timeout) {
45   using namespace std::chrono;
46   m_end_time = steady_clock::time_point(steady_clock::now() + timeout);
47 }
48
49 void SelectHelper::FDSetRead(lldb::socket_t fd) {
50   m_fd_map[fd].read_set = true;
51 }
52
53 void SelectHelper::FDSetWrite(lldb::socket_t fd) {
54   m_fd_map[fd].write_set = true;
55 }
56
57 void SelectHelper::FDSetError(lldb::socket_t fd) {
58   m_fd_map[fd].error_set = true;
59 }
60
61 bool SelectHelper::FDIsSetRead(lldb::socket_t fd) const {
62   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;
67 }
68
69 bool SelectHelper::FDIsSetWrite(lldb::socket_t fd) const {
70   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;
75 }
76
77 bool SelectHelper::FDIsSetError(lldb::socket_t fd) const {
78   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;
83 }
84
85 static 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
93 lldb_private::Error SelectHelper::Select() {
94   lldb_private::Error error;
95 #ifdef _MSC_VER
96   // 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)
100     return lldb_private::Error("Too many file descriptors for select()");
101 #endif
102
103   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;
107   for (auto &pair : m_fd_map) {
108     pair.second.PrepareForSelect();
109     const lldb::socket_t fd = pair.first;
110 #if !defined(__APPLE__) && !defined(_MSC_VER)
111     lldbassert(fd < FD_SETSIZE);
112     if (fd >= FD_SETSIZE) {
113       error.SetErrorStringWithFormat("%i is too large for select()", fd);
114       return error;
115     }
116 #endif
117     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);
124   }
125
126   if (!max_fd.hasValue()) {
127     error.SetErrorString("no valid file descriptors");
128     return error;
129   }
130
131   const unsigned nfds = static_cast<unsigned>(*max_fd) + 1;
132   fd_set *read_fdset_ptr = nullptr;
133   fd_set *write_fdset_ptr = nullptr;
134   fd_set *error_fdset_ptr = nullptr;
135 //----------------------------------------------------------------------
136 // Initialize and zero out the fdsets
137 //----------------------------------------------------------------------
138 #if defined(__APPLE__)
139   llvm::SmallVector<fd_set, 1> read_fdset;
140   llvm::SmallVector<fd_set, 1> write_fdset;
141   llvm::SmallVector<fd_set, 1> error_fdset;
142
143   if (max_read_fd.hasValue()) {
144     read_fdset.resize((nfds / FD_SETSIZE) + 1);
145     read_fdset_ptr = read_fdset.data();
146   }
147   if (max_write_fd.hasValue()) {
148     write_fdset.resize((nfds / FD_SETSIZE) + 1);
149     write_fdset_ptr = write_fdset.data();
150   }
151   if (max_error_fd.hasValue()) {
152     error_fdset.resize((nfds / FD_SETSIZE) + 1);
153     error_fdset_ptr = error_fdset.data();
154   }
155   for (auto &fd_set : read_fdset)
156     FD_ZERO(&fd_set);
157   for (auto &fd_set : write_fdset)
158     FD_ZERO(&fd_set);
159   for (auto &fd_set : error_fdset)
160     FD_ZERO(&fd_set);
161 #else
162   fd_set read_fdset;
163   fd_set write_fdset;
164   fd_set error_fdset;
165
166   if (max_read_fd.hasValue()) {
167     FD_ZERO(&read_fdset);
168     read_fdset_ptr = &read_fdset;
169   }
170   if (max_write_fd.hasValue()) {
171     FD_ZERO(&write_fdset);
172     write_fdset_ptr = &write_fdset;
173   }
174   if (max_error_fd.hasValue()) {
175     FD_ZERO(&error_fdset);
176     error_fdset_ptr = &error_fdset;
177   }
178 #endif
179   //----------------------------------------------------------------------
180   // Set the FD bits in the fdsets for read/write/error
181   //----------------------------------------------------------------------
182   for (auto &pair : m_fd_map) {
183     const lldb::socket_t fd = pair.first;
184
185     if (pair.second.read_set)
186       FD_SET(fd, read_fdset_ptr);
187
188     if (pair.second.write_set)
189       FD_SET(fd, write_fdset_ptr);
190
191     if (pair.second.error_set)
192       FD_SET(fd, error_fdset_ptr);
193   }
194
195   //----------------------------------------------------------------------
196   // Setup our timeout time value if needed
197   //----------------------------------------------------------------------
198   struct timeval *tv_ptr = nullptr;
199   struct timeval tv = {0, 0};
200
201   while (1) {
202     using namespace std::chrono;
203     //------------------------------------------------------------------
204     // Setup out relative timeout based on the end time if we have one
205     //------------------------------------------------------------------
206     if (m_end_time.hasValue()) {
207       tv_ptr = &tv;
208       const auto remaining_dur = duration_cast<microseconds>(
209           m_end_time.getValue() - steady_clock::now());
210       if (remaining_dur.count() > 0) {
211         // Wait for a specific amount of time
212         const auto dur_secs = duration_cast<seconds>(remaining_dur);
213         const auto dur_usecs = remaining_dur % seconds(1);
214         tv.tv_sec = dur_secs.count();
215         tv.tv_usec = dur_usecs.count();
216       } else {
217         // Just poll once with no timeout
218         tv.tv_sec = 0;
219         tv.tv_usec = 0;
220       }
221     }
222     const int num_set_fds = ::select(nfds, read_fdset_ptr, write_fdset_ptr,
223                                      error_fdset_ptr, tv_ptr);
224     if (num_set_fds < 0) {
225       // We got an error
226       error.SetErrorToErrno();
227       if (error.GetError() == EINTR) {
228         error.Clear();
229         continue; // Keep calling select if we get EINTR
230       } else
231         return error;
232     } else if (num_set_fds == 0) {
233       // Timeout
234       error.SetError(ETIMEDOUT, lldb::eErrorTypePOSIX);
235       error.SetErrorString("timed out");
236       return error;
237     } else {
238       // One or more descriptors were set, update the FDInfo::select_is_set mask
239       // so users can ask the SelectHelper class so clients can call one of:
240
241       for (auto &pair : m_fd_map) {
242         const int fd = pair.first;
243
244         if (pair.second.read_set) {
245           if (FD_ISSET(fd, read_fdset_ptr))
246             pair.second.read_is_set = true;
247         }
248         if (pair.second.write_set) {
249           if (FD_ISSET(fd, write_fdset_ptr))
250             pair.second.write_is_set = true;
251         }
252         if (pair.second.error_set) {
253           if (FD_ISSET(fd, error_fdset_ptr))
254             pair.second.error_is_set = true;
255         }
256       }
257       break;
258     }
259   }
260   return error;
261 }