1435933ddSDimitry Andric //===-- SelectHelper.cpp ----------------------------------------*- C++ -*-===//
2435933ddSDimitry Andric //
3435933ddSDimitry Andric //                     The LLVM Compiler Infrastructure
4435933ddSDimitry Andric //
5435933ddSDimitry Andric // This file is distributed under the University of Illinois Open Source
6435933ddSDimitry Andric // License. See LICENSE.TXT for details.
7435933ddSDimitry Andric //
8435933ddSDimitry Andric //===----------------------------------------------------------------------===//
9435933ddSDimitry Andric 
10435933ddSDimitry Andric #if defined(__APPLE__)
11435933ddSDimitry Andric // Enable this special support for Apple builds where we can have unlimited
12435933ddSDimitry Andric // select bounds. We tried switching to poll() and kqueue and we were panicing
13435933ddSDimitry Andric // the kernel, so we have to stick with select for now.
14435933ddSDimitry Andric #define _DARWIN_UNLIMITED_SELECT
15435933ddSDimitry Andric #endif
16435933ddSDimitry Andric 
17f678e45dSDimitry Andric #include "lldb/Utility/SelectHelper.h"
18f678e45dSDimitry Andric #include "lldb/Utility/LLDBAssert.h"
195517e702SDimitry Andric #include "lldb/Utility/Status.h"
20*b5893f02SDimitry Andric #include "lldb/lldb-enumerations.h"
21*b5893f02SDimitry Andric #include "lldb/lldb-types.h"
22f678e45dSDimitry Andric 
23*b5893f02SDimitry Andric #include "llvm/ADT/DenseMap.h"
24*b5893f02SDimitry Andric #include "llvm/ADT/Optional.h"
25f678e45dSDimitry Andric 
26f678e45dSDimitry Andric #include <algorithm>
27*b5893f02SDimitry Andric #include <chrono>
28f678e45dSDimitry Andric 
29435933ddSDimitry Andric #include <errno.h>
30435933ddSDimitry Andric #if defined(_WIN32)
31435933ddSDimitry Andric // Define NOMINMAX to avoid macros that conflict with std::min and std::max
32435933ddSDimitry Andric #define NOMINMAX
33435933ddSDimitry Andric #include <winsock2.h>
34435933ddSDimitry Andric #else
35acac075bSDimitry Andric #include <sys/time.h>
36435933ddSDimitry Andric #include <sys/select.h>
37435933ddSDimitry Andric #endif
38435933ddSDimitry Andric 
39435933ddSDimitry Andric 
SelectHelper()40435933ddSDimitry Andric SelectHelper::SelectHelper()
41435933ddSDimitry Andric     : m_fd_map(), m_end_time() // Infinite timeout unless
42435933ddSDimitry Andric                                // SelectHelper::SetTimeout() gets called
43435933ddSDimitry Andric {}
44435933ddSDimitry Andric 
SetTimeout(const std::chrono::microseconds & timeout)45435933ddSDimitry Andric void SelectHelper::SetTimeout(const std::chrono::microseconds &timeout) {
46435933ddSDimitry Andric   using namespace std::chrono;
47435933ddSDimitry Andric   m_end_time = steady_clock::time_point(steady_clock::now() + timeout);
48435933ddSDimitry Andric }
49435933ddSDimitry Andric 
FDSetRead(lldb::socket_t fd)50435933ddSDimitry Andric void SelectHelper::FDSetRead(lldb::socket_t fd) {
51435933ddSDimitry Andric   m_fd_map[fd].read_set = true;
52435933ddSDimitry Andric }
53435933ddSDimitry Andric 
FDSetWrite(lldb::socket_t fd)54435933ddSDimitry Andric void SelectHelper::FDSetWrite(lldb::socket_t fd) {
55435933ddSDimitry Andric   m_fd_map[fd].write_set = true;
56435933ddSDimitry Andric }
57435933ddSDimitry Andric 
FDSetError(lldb::socket_t fd)58435933ddSDimitry Andric void SelectHelper::FDSetError(lldb::socket_t fd) {
59435933ddSDimitry Andric   m_fd_map[fd].error_set = true;
60435933ddSDimitry Andric }
61435933ddSDimitry Andric 
FDIsSetRead(lldb::socket_t fd) const62435933ddSDimitry Andric bool SelectHelper::FDIsSetRead(lldb::socket_t fd) const {
63435933ddSDimitry Andric   auto pos = m_fd_map.find(fd);
64435933ddSDimitry Andric   if (pos != m_fd_map.end())
65435933ddSDimitry Andric     return pos->second.read_is_set;
66435933ddSDimitry Andric   else
67435933ddSDimitry Andric     return false;
68435933ddSDimitry Andric }
69435933ddSDimitry Andric 
FDIsSetWrite(lldb::socket_t fd) const70435933ddSDimitry Andric bool SelectHelper::FDIsSetWrite(lldb::socket_t fd) const {
71435933ddSDimitry Andric   auto pos = m_fd_map.find(fd);
72435933ddSDimitry Andric   if (pos != m_fd_map.end())
73435933ddSDimitry Andric     return pos->second.write_is_set;
74435933ddSDimitry Andric   else
75435933ddSDimitry Andric     return false;
76435933ddSDimitry Andric }
77435933ddSDimitry Andric 
FDIsSetError(lldb::socket_t fd) const78435933ddSDimitry Andric bool SelectHelper::FDIsSetError(lldb::socket_t fd) const {
79435933ddSDimitry Andric   auto pos = m_fd_map.find(fd);
80435933ddSDimitry Andric   if (pos != m_fd_map.end())
81435933ddSDimitry Andric     return pos->second.error_is_set;
82435933ddSDimitry Andric   else
83435933ddSDimitry Andric     return false;
84435933ddSDimitry Andric }
85435933ddSDimitry Andric 
updateMaxFd(llvm::Optional<lldb::socket_t> & vold,lldb::socket_t vnew)86435933ddSDimitry Andric static void updateMaxFd(llvm::Optional<lldb::socket_t> &vold,
87435933ddSDimitry Andric                         lldb::socket_t vnew) {
88435933ddSDimitry Andric   if (!vold.hasValue())
89435933ddSDimitry Andric     vold = vnew;
90435933ddSDimitry Andric   else
91435933ddSDimitry Andric     vold = std::max(*vold, vnew);
92435933ddSDimitry Andric }
93435933ddSDimitry Andric 
Select()945517e702SDimitry Andric lldb_private::Status SelectHelper::Select() {
955517e702SDimitry Andric   lldb_private::Status error;
96435933ddSDimitry Andric #ifdef _MSC_VER
97435933ddSDimitry Andric   // On windows FD_SETSIZE limits the number of file descriptors, not their
98435933ddSDimitry Andric   // numeric value.
99435933ddSDimitry Andric   lldbassert(m_fd_map.size() <= FD_SETSIZE);
100435933ddSDimitry Andric   if (m_fd_map.size() > FD_SETSIZE)
1015517e702SDimitry Andric     return lldb_private::Status("Too many file descriptors for select()");
102435933ddSDimitry Andric #endif
103435933ddSDimitry Andric 
104435933ddSDimitry Andric   llvm::Optional<lldb::socket_t> max_read_fd;
105435933ddSDimitry Andric   llvm::Optional<lldb::socket_t> max_write_fd;
106435933ddSDimitry Andric   llvm::Optional<lldb::socket_t> max_error_fd;
107435933ddSDimitry Andric   llvm::Optional<lldb::socket_t> max_fd;
108435933ddSDimitry Andric   for (auto &pair : m_fd_map) {
109435933ddSDimitry Andric     pair.second.PrepareForSelect();
110435933ddSDimitry Andric     const lldb::socket_t fd = pair.first;
111435933ddSDimitry Andric #if !defined(__APPLE__) && !defined(_MSC_VER)
1124ba319b5SDimitry Andric     lldbassert(fd < static_cast<int>(FD_SETSIZE));
1134ba319b5SDimitry Andric     if (fd >= static_cast<int>(FD_SETSIZE)) {
114435933ddSDimitry Andric       error.SetErrorStringWithFormat("%i is too large for select()", fd);
115435933ddSDimitry Andric       return error;
116435933ddSDimitry Andric     }
117435933ddSDimitry Andric #endif
118435933ddSDimitry Andric     if (pair.second.read_set)
119435933ddSDimitry Andric       updateMaxFd(max_read_fd, fd);
120435933ddSDimitry Andric     if (pair.second.write_set)
121435933ddSDimitry Andric       updateMaxFd(max_write_fd, fd);
122435933ddSDimitry Andric     if (pair.second.error_set)
123435933ddSDimitry Andric       updateMaxFd(max_error_fd, fd);
124435933ddSDimitry Andric     updateMaxFd(max_fd, fd);
125435933ddSDimitry Andric   }
126435933ddSDimitry Andric 
127435933ddSDimitry Andric   if (!max_fd.hasValue()) {
128435933ddSDimitry Andric     error.SetErrorString("no valid file descriptors");
129435933ddSDimitry Andric     return error;
130435933ddSDimitry Andric   }
131435933ddSDimitry Andric 
132435933ddSDimitry Andric   const unsigned nfds = static_cast<unsigned>(*max_fd) + 1;
133435933ddSDimitry Andric   fd_set *read_fdset_ptr = nullptr;
134435933ddSDimitry Andric   fd_set *write_fdset_ptr = nullptr;
135435933ddSDimitry Andric   fd_set *error_fdset_ptr = nullptr;
136435933ddSDimitry Andric //----------------------------------------------------------------------
137435933ddSDimitry Andric // Initialize and zero out the fdsets
138435933ddSDimitry Andric //----------------------------------------------------------------------
139435933ddSDimitry Andric #if defined(__APPLE__)
140435933ddSDimitry Andric   llvm::SmallVector<fd_set, 1> read_fdset;
141435933ddSDimitry Andric   llvm::SmallVector<fd_set, 1> write_fdset;
142435933ddSDimitry Andric   llvm::SmallVector<fd_set, 1> error_fdset;
143435933ddSDimitry Andric 
144435933ddSDimitry Andric   if (max_read_fd.hasValue()) {
145435933ddSDimitry Andric     read_fdset.resize((nfds / FD_SETSIZE) + 1);
146435933ddSDimitry Andric     read_fdset_ptr = read_fdset.data();
147435933ddSDimitry Andric   }
148435933ddSDimitry Andric   if (max_write_fd.hasValue()) {
149435933ddSDimitry Andric     write_fdset.resize((nfds / FD_SETSIZE) + 1);
150435933ddSDimitry Andric     write_fdset_ptr = write_fdset.data();
151435933ddSDimitry Andric   }
152435933ddSDimitry Andric   if (max_error_fd.hasValue()) {
153435933ddSDimitry Andric     error_fdset.resize((nfds / FD_SETSIZE) + 1);
154435933ddSDimitry Andric     error_fdset_ptr = error_fdset.data();
155435933ddSDimitry Andric   }
156435933ddSDimitry Andric   for (auto &fd_set : read_fdset)
157435933ddSDimitry Andric     FD_ZERO(&fd_set);
158435933ddSDimitry Andric   for (auto &fd_set : write_fdset)
159435933ddSDimitry Andric     FD_ZERO(&fd_set);
160435933ddSDimitry Andric   for (auto &fd_set : error_fdset)
161435933ddSDimitry Andric     FD_ZERO(&fd_set);
162435933ddSDimitry Andric #else
163435933ddSDimitry Andric   fd_set read_fdset;
164435933ddSDimitry Andric   fd_set write_fdset;
165435933ddSDimitry Andric   fd_set error_fdset;
166435933ddSDimitry Andric 
167435933ddSDimitry Andric   if (max_read_fd.hasValue()) {
168435933ddSDimitry Andric     FD_ZERO(&read_fdset);
169435933ddSDimitry Andric     read_fdset_ptr = &read_fdset;
170435933ddSDimitry Andric   }
171435933ddSDimitry Andric   if (max_write_fd.hasValue()) {
172435933ddSDimitry Andric     FD_ZERO(&write_fdset);
173435933ddSDimitry Andric     write_fdset_ptr = &write_fdset;
174435933ddSDimitry Andric   }
175435933ddSDimitry Andric   if (max_error_fd.hasValue()) {
176435933ddSDimitry Andric     FD_ZERO(&error_fdset);
177435933ddSDimitry Andric     error_fdset_ptr = &error_fdset;
178435933ddSDimitry Andric   }
179435933ddSDimitry Andric #endif
180435933ddSDimitry Andric   //----------------------------------------------------------------------
181435933ddSDimitry Andric   // Set the FD bits in the fdsets for read/write/error
182435933ddSDimitry Andric   //----------------------------------------------------------------------
183435933ddSDimitry Andric   for (auto &pair : m_fd_map) {
184435933ddSDimitry Andric     const lldb::socket_t fd = pair.first;
185435933ddSDimitry Andric 
186435933ddSDimitry Andric     if (pair.second.read_set)
187435933ddSDimitry Andric       FD_SET(fd, read_fdset_ptr);
188435933ddSDimitry Andric 
189435933ddSDimitry Andric     if (pair.second.write_set)
190435933ddSDimitry Andric       FD_SET(fd, write_fdset_ptr);
191435933ddSDimitry Andric 
192435933ddSDimitry Andric     if (pair.second.error_set)
193435933ddSDimitry Andric       FD_SET(fd, error_fdset_ptr);
194435933ddSDimitry Andric   }
195435933ddSDimitry Andric 
196435933ddSDimitry Andric   //----------------------------------------------------------------------
197435933ddSDimitry Andric   // Setup our timeout time value if needed
198435933ddSDimitry Andric   //----------------------------------------------------------------------
199435933ddSDimitry Andric   struct timeval *tv_ptr = nullptr;
200435933ddSDimitry Andric   struct timeval tv = {0, 0};
201435933ddSDimitry Andric 
202435933ddSDimitry Andric   while (1) {
203435933ddSDimitry Andric     using namespace std::chrono;
204435933ddSDimitry Andric     //------------------------------------------------------------------
205435933ddSDimitry Andric     // Setup out relative timeout based on the end time if we have one
206435933ddSDimitry Andric     //------------------------------------------------------------------
207435933ddSDimitry Andric     if (m_end_time.hasValue()) {
208435933ddSDimitry Andric       tv_ptr = &tv;
209435933ddSDimitry Andric       const auto remaining_dur = duration_cast<microseconds>(
210435933ddSDimitry Andric           m_end_time.getValue() - steady_clock::now());
211435933ddSDimitry Andric       if (remaining_dur.count() > 0) {
212435933ddSDimitry Andric         // Wait for a specific amount of time
213435933ddSDimitry Andric         const auto dur_secs = duration_cast<seconds>(remaining_dur);
214435933ddSDimitry Andric         const auto dur_usecs = remaining_dur % seconds(1);
215435933ddSDimitry Andric         tv.tv_sec = dur_secs.count();
216435933ddSDimitry Andric         tv.tv_usec = dur_usecs.count();
217435933ddSDimitry Andric       } else {
218435933ddSDimitry Andric         // Just poll once with no timeout
219435933ddSDimitry Andric         tv.tv_sec = 0;
220435933ddSDimitry Andric         tv.tv_usec = 0;
221435933ddSDimitry Andric       }
222435933ddSDimitry Andric     }
223435933ddSDimitry Andric     const int num_set_fds = ::select(nfds, read_fdset_ptr, write_fdset_ptr,
224435933ddSDimitry Andric                                      error_fdset_ptr, tv_ptr);
225435933ddSDimitry Andric     if (num_set_fds < 0) {
226435933ddSDimitry Andric       // We got an error
227435933ddSDimitry Andric       error.SetErrorToErrno();
228435933ddSDimitry Andric       if (error.GetError() == EINTR) {
229435933ddSDimitry Andric         error.Clear();
230435933ddSDimitry Andric         continue; // Keep calling select if we get EINTR
231435933ddSDimitry Andric       } else
232435933ddSDimitry Andric         return error;
233435933ddSDimitry Andric     } else if (num_set_fds == 0) {
234435933ddSDimitry Andric       // Timeout
235435933ddSDimitry Andric       error.SetError(ETIMEDOUT, lldb::eErrorTypePOSIX);
236435933ddSDimitry Andric       error.SetErrorString("timed out");
237435933ddSDimitry Andric       return error;
238435933ddSDimitry Andric     } else {
2394ba319b5SDimitry Andric       // One or more descriptors were set, update the FDInfo::select_is_set
2404ba319b5SDimitry Andric       // mask so users can ask the SelectHelper class so clients can call one
2414ba319b5SDimitry Andric       // of:
242435933ddSDimitry Andric 
243435933ddSDimitry Andric       for (auto &pair : m_fd_map) {
244435933ddSDimitry Andric         const int fd = pair.first;
245435933ddSDimitry Andric 
246435933ddSDimitry Andric         if (pair.second.read_set) {
247435933ddSDimitry Andric           if (FD_ISSET(fd, read_fdset_ptr))
248435933ddSDimitry Andric             pair.second.read_is_set = true;
249435933ddSDimitry Andric         }
250435933ddSDimitry Andric         if (pair.second.write_set) {
251435933ddSDimitry Andric           if (FD_ISSET(fd, write_fdset_ptr))
252435933ddSDimitry Andric             pair.second.write_is_set = true;
253435933ddSDimitry Andric         }
254435933ddSDimitry Andric         if (pair.second.error_set) {
255435933ddSDimitry Andric           if (FD_ISSET(fd, error_fdset_ptr))
256435933ddSDimitry Andric             pair.second.error_is_set = true;
257435933ddSDimitry Andric         }
258435933ddSDimitry Andric       }
259435933ddSDimitry Andric       break;
260435933ddSDimitry Andric     }
261435933ddSDimitry Andric   }
262435933ddSDimitry Andric   return error;
263435933ddSDimitry Andric }
264