1ee1f578dSGreg Clayton //===-- SelectHelper.cpp ----------------------------------------*- C++ -*-===//
2ee1f578dSGreg Clayton //
3ee1f578dSGreg Clayton //                     The LLVM Compiler Infrastructure
4ee1f578dSGreg Clayton //
5ee1f578dSGreg Clayton // This file is distributed under the University of Illinois Open Source
6ee1f578dSGreg Clayton // License. See LICENSE.TXT for details.
7ee1f578dSGreg Clayton //
8ee1f578dSGreg Clayton //===----------------------------------------------------------------------===//
9ee1f578dSGreg Clayton 
10ee1f578dSGreg Clayton #if defined(__APPLE__)
11ee1f578dSGreg Clayton // Enable this special support for Apple builds where we can have unlimited
12ee1f578dSGreg Clayton // select bounds. We tried switching to poll() and kqueue and we were panicing
13ee1f578dSGreg Clayton // the kernel, so we have to stick with select for now.
14ee1f578dSGreg Clayton #define _DARWIN_UNLIMITED_SELECT
15ee1f578dSGreg Clayton #endif
16ee1f578dSGreg Clayton 
17ee1f578dSGreg Clayton // C Includes
18ee1f578dSGreg Clayton #include <errno.h>
19ee1f578dSGreg Clayton #if defined(_WIN32)
20ee1f578dSGreg Clayton // Define NOMINMAX to avoid macros that conflict with std::min and std::max
21ee1f578dSGreg Clayton #define NOMINMAX
22ee1f578dSGreg Clayton #include <winsock2.h>
23ee1f578dSGreg Clayton #else
24ee1f578dSGreg Clayton #include <sys/select.h>
25ee1f578dSGreg Clayton #endif
26ee1f578dSGreg Clayton 
27ee1f578dSGreg Clayton // C++ Includes
28ee1f578dSGreg Clayton #include <algorithm>
29ee1f578dSGreg Clayton 
30ee1f578dSGreg Clayton // Other libraries and framework includes
31ee1f578dSGreg Clayton #include "llvm/ADT/SmallVector.h"
32ee1f578dSGreg Clayton 
33ee1f578dSGreg Clayton // Project includes
34ee1f578dSGreg Clayton #include "lldb/Core/Error.h"
35ee1f578dSGreg Clayton #include "lldb/Utility/SelectHelper.h"
36ee1f578dSGreg Clayton #include "lldb/Utility/LLDBAssert.h"
37ee1f578dSGreg Clayton 
38ee1f578dSGreg Clayton SelectHelper::SelectHelper() :
39ee1f578dSGreg Clayton     m_fd_map(),
40ee1f578dSGreg Clayton     m_end_time() // Infinite timeout unless SelectHelper::SetTimeout() gets called
41ee1f578dSGreg Clayton {
42ee1f578dSGreg Clayton }
43ee1f578dSGreg Clayton 
44ee1f578dSGreg Clayton void
45ee1f578dSGreg Clayton SelectHelper::SetTimeout(const std::chrono::microseconds &timeout)
46ee1f578dSGreg Clayton {
47ee1f578dSGreg Clayton     using namespace std::chrono;
48ee1f578dSGreg Clayton     m_end_time = steady_clock::time_point(steady_clock::now() + timeout);
49ee1f578dSGreg Clayton }
50ee1f578dSGreg Clayton 
51ee1f578dSGreg Clayton void
52ee1f578dSGreg Clayton SelectHelper::FDSetRead(int fd)
53ee1f578dSGreg Clayton {
54ee1f578dSGreg Clayton     m_fd_map[fd].read_set = true;
55ee1f578dSGreg Clayton }
56ee1f578dSGreg Clayton 
57ee1f578dSGreg Clayton void
58ee1f578dSGreg Clayton SelectHelper::FDSetWrite(int fd)
59ee1f578dSGreg Clayton {
60ee1f578dSGreg Clayton     m_fd_map[fd].write_set = true;
61ee1f578dSGreg Clayton }
62ee1f578dSGreg Clayton 
63ee1f578dSGreg Clayton void
64ee1f578dSGreg Clayton SelectHelper::FDSetError(int fd)
65ee1f578dSGreg Clayton {
66ee1f578dSGreg Clayton     m_fd_map[fd].error_set = true;
67ee1f578dSGreg Clayton }
68ee1f578dSGreg Clayton 
69ee1f578dSGreg Clayton bool
70ee1f578dSGreg Clayton SelectHelper::FDIsSetRead(int fd) const
71ee1f578dSGreg Clayton {
72ee1f578dSGreg Clayton     auto pos = m_fd_map.find(fd);
73ee1f578dSGreg Clayton     if (pos != m_fd_map.end())
74ee1f578dSGreg Clayton         return pos->second.read_is_set;
75ee1f578dSGreg Clayton     else
76ee1f578dSGreg Clayton         return false;
77ee1f578dSGreg Clayton }
78ee1f578dSGreg Clayton 
79ee1f578dSGreg Clayton bool
80ee1f578dSGreg Clayton SelectHelper::FDIsSetWrite(int fd) const
81ee1f578dSGreg Clayton {
82ee1f578dSGreg Clayton     auto pos = m_fd_map.find(fd);
83ee1f578dSGreg Clayton     if (pos != m_fd_map.end())
84ee1f578dSGreg Clayton         return pos->second.write_is_set;
85ee1f578dSGreg Clayton     else
86ee1f578dSGreg Clayton         return false;
87ee1f578dSGreg Clayton }
88ee1f578dSGreg Clayton 
89ee1f578dSGreg Clayton bool
90ee1f578dSGreg Clayton SelectHelper::FDIsSetError(int fd) const
91ee1f578dSGreg Clayton {
92ee1f578dSGreg Clayton     auto pos = m_fd_map.find(fd);
93ee1f578dSGreg Clayton     if (pos != m_fd_map.end())
94ee1f578dSGreg Clayton         return pos->second.error_is_set;
95ee1f578dSGreg Clayton     else
96ee1f578dSGreg Clayton         return false;
97ee1f578dSGreg Clayton }
98ee1f578dSGreg Clayton 
99ee1f578dSGreg Clayton lldb_private::Error
100ee1f578dSGreg Clayton SelectHelper::Select()
101ee1f578dSGreg Clayton {
102ee1f578dSGreg Clayton     lldb_private::Error error;
103*fdb2d99eSPavel Labath #ifdef _MSC_VER
104*fdb2d99eSPavel Labath     // On windows FD_SETSIZE limits the number of file descriptors, not their numeric value.
105*fdb2d99eSPavel Labath     lldbassert(m_fd_map.size() <= FD_SETSIZE);
106*fdb2d99eSPavel Labath     if (m_fd_map.size() > FD_SETSIZE)
107*fdb2d99eSPavel Labath         return lldb_private::Error("Too many file descriptors for select()");
108*fdb2d99eSPavel Labath #endif
109ee1f578dSGreg Clayton 
110ee1f578dSGreg Clayton     int max_read_fd = -1;
111ee1f578dSGreg Clayton     int max_write_fd = -1;
112ee1f578dSGreg Clayton     int max_error_fd = -1;
113ee1f578dSGreg Clayton     int max_fd = -1;
114ee1f578dSGreg Clayton     for (auto &pair : m_fd_map)
115ee1f578dSGreg Clayton     {
116ee1f578dSGreg Clayton         pair.second.PrepareForSelect();
117ee1f578dSGreg Clayton         const int fd = pair.first;
118*fdb2d99eSPavel Labath #if !defined(__APPLE__) && !defined(_MSC_VER)
119ee1f578dSGreg Clayton         lldbassert(fd < FD_SETSIZE);
120ee1f578dSGreg Clayton         if (fd >= FD_SETSIZE)
121ee1f578dSGreg Clayton         {
122ee1f578dSGreg Clayton             error.SetErrorStringWithFormat("%i is too large for select()", fd);
123ee1f578dSGreg Clayton             return error;
124ee1f578dSGreg Clayton         }
125ee1f578dSGreg Clayton #endif
126ee1f578dSGreg Clayton         if (pair.second.read_set)
127ee1f578dSGreg Clayton         {
128ee1f578dSGreg Clayton             max_read_fd = std::max<int>(fd, max_read_fd);
129ee1f578dSGreg Clayton             max_fd = std::max<int>(fd, max_fd);
130ee1f578dSGreg Clayton         }
131ee1f578dSGreg Clayton         if (pair.second.write_set)
132ee1f578dSGreg Clayton         {
133ee1f578dSGreg Clayton             max_write_fd = std::max<int>(fd, max_write_fd);
134ee1f578dSGreg Clayton             max_fd = std::max<int>(fd, max_fd);
135ee1f578dSGreg Clayton         }
136ee1f578dSGreg Clayton         if (pair.second.error_set)
137ee1f578dSGreg Clayton         {
138ee1f578dSGreg Clayton             max_error_fd = std::max<int>(fd, max_error_fd);
139ee1f578dSGreg Clayton             max_fd = std::max<int>(fd, max_fd);
140ee1f578dSGreg Clayton         }
141ee1f578dSGreg Clayton     }
142ee1f578dSGreg Clayton 
143ee1f578dSGreg Clayton     if (max_fd == -1)
144ee1f578dSGreg Clayton     {
145ee1f578dSGreg Clayton         error.SetErrorString("no valid file descriptors");
146ee1f578dSGreg Clayton         return error;
147ee1f578dSGreg Clayton     }
148ee1f578dSGreg Clayton 
149ee1f578dSGreg Clayton     const int nfds = max_fd + 1;
150ee1f578dSGreg Clayton     fd_set *read_fdset_ptr = nullptr;
151ee1f578dSGreg Clayton     fd_set *write_fdset_ptr = nullptr;
152ee1f578dSGreg Clayton     fd_set *error_fdset_ptr = nullptr;
153ee1f578dSGreg Clayton     //----------------------------------------------------------------------
154ee1f578dSGreg Clayton     // Initialize and zero out the fdsets
155ee1f578dSGreg Clayton     //----------------------------------------------------------------------
156ee1f578dSGreg Clayton #if defined(__APPLE__)
157ee1f578dSGreg Clayton     llvm::SmallVector<fd_set, 1> read_fdset;
158ee1f578dSGreg Clayton     llvm::SmallVector<fd_set, 1> write_fdset;
159ee1f578dSGreg Clayton     llvm::SmallVector<fd_set, 1> error_fdset;
160ee1f578dSGreg Clayton 
161ee1f578dSGreg Clayton     if (max_read_fd >= 0)
162ee1f578dSGreg Clayton     {
163ee1f578dSGreg Clayton         read_fdset.resize((nfds / FD_SETSIZE) + 1);
164ee1f578dSGreg Clayton         read_fdset_ptr = read_fdset.data();
165ee1f578dSGreg Clayton     }
166ee1f578dSGreg Clayton     if (max_write_fd >= 0)
167ee1f578dSGreg Clayton     {
168ee1f578dSGreg Clayton         write_fdset.resize((nfds / FD_SETSIZE) + 1);
169ee1f578dSGreg Clayton         write_fdset_ptr = write_fdset.data();
170ee1f578dSGreg Clayton     }
171ee1f578dSGreg Clayton     if (max_error_fd >= 0)
172ee1f578dSGreg Clayton     {
173ee1f578dSGreg Clayton         error_fdset.resize((nfds / FD_SETSIZE) + 1);
174ee1f578dSGreg Clayton         error_fdset_ptr = error_fdset.data();
175ee1f578dSGreg Clayton     }
176ee1f578dSGreg Clayton     for (auto &fd_set : read_fdset)
177ee1f578dSGreg Clayton         FD_ZERO(&fd_set);
178ee1f578dSGreg Clayton     for (auto &fd_set : write_fdset)
179ee1f578dSGreg Clayton         FD_ZERO(&fd_set);
180ee1f578dSGreg Clayton     for (auto &fd_set : error_fdset)
181ee1f578dSGreg Clayton         FD_ZERO(&fd_set);
182ee1f578dSGreg Clayton #else
183ee1f578dSGreg Clayton     fd_set read_fdset;
184ee1f578dSGreg Clayton     fd_set write_fdset;
185ee1f578dSGreg Clayton     fd_set error_fdset;
186ee1f578dSGreg Clayton 
187ee1f578dSGreg Clayton     if (max_read_fd >= 0)
188ee1f578dSGreg Clayton     {
189ee1f578dSGreg Clayton         FD_ZERO(&read_fdset);
190ee1f578dSGreg Clayton         read_fdset_ptr = &read_fdset;
191ee1f578dSGreg Clayton     }
192ee1f578dSGreg Clayton     if (max_write_fd >= 0)
193ee1f578dSGreg Clayton     {
194ee1f578dSGreg Clayton         FD_ZERO(&write_fdset);
195ee1f578dSGreg Clayton         write_fdset_ptr = &write_fdset;
196ee1f578dSGreg Clayton     }
197ee1f578dSGreg Clayton     if (max_error_fd >= 0)
198ee1f578dSGreg Clayton     {
199ee1f578dSGreg Clayton         FD_ZERO(&error_fdset);
200ee1f578dSGreg Clayton         error_fdset_ptr = &error_fdset;
201ee1f578dSGreg Clayton     }
202ee1f578dSGreg Clayton #endif
203ee1f578dSGreg Clayton     //----------------------------------------------------------------------
204ee1f578dSGreg Clayton     // Set the FD bits in the fdsets for read/write/error
205ee1f578dSGreg Clayton     //----------------------------------------------------------------------
206ee1f578dSGreg Clayton     for (auto &pair : m_fd_map)
207ee1f578dSGreg Clayton     {
208ee1f578dSGreg Clayton         const int fd = pair.first;
209ee1f578dSGreg Clayton 
210ee1f578dSGreg Clayton         if (pair.second.read_set)
211ee1f578dSGreg Clayton             FD_SET(fd, read_fdset_ptr);
212ee1f578dSGreg Clayton 
213ee1f578dSGreg Clayton         if (pair.second.write_set)
214ee1f578dSGreg Clayton             FD_SET(fd, write_fdset_ptr);
215ee1f578dSGreg Clayton 
216ee1f578dSGreg Clayton         if (pair.second.error_set)
217ee1f578dSGreg Clayton             FD_SET(fd, error_fdset_ptr);
218ee1f578dSGreg Clayton     }
219ee1f578dSGreg Clayton 
220ee1f578dSGreg Clayton     //----------------------------------------------------------------------
221ee1f578dSGreg Clayton     // Setup our timeout time value if needed
222ee1f578dSGreg Clayton     //----------------------------------------------------------------------
223ee1f578dSGreg Clayton     struct timeval *tv_ptr = nullptr;
224ee1f578dSGreg Clayton     struct timeval tv = {0, 0};
225ee1f578dSGreg Clayton 
226ee1f578dSGreg Clayton     while (1)
227ee1f578dSGreg Clayton     {
228ee1f578dSGreg Clayton         using namespace std::chrono;
229ee1f578dSGreg Clayton         //------------------------------------------------------------------
230ee1f578dSGreg Clayton         // Setup out relative timeout based on the end time if we have one
231ee1f578dSGreg Clayton         //------------------------------------------------------------------
232ee1f578dSGreg Clayton         if (m_end_time.hasValue())
233ee1f578dSGreg Clayton         {
234ee1f578dSGreg Clayton             tv_ptr = &tv;
235ee1f578dSGreg Clayton             const auto remaining_dur = duration_cast<microseconds>(m_end_time.getValue() - steady_clock::now());
236ee1f578dSGreg Clayton             if (remaining_dur.count() > 0)
237ee1f578dSGreg Clayton             {
238ee1f578dSGreg Clayton                 // Wait for a specific amount of time
239ee1f578dSGreg Clayton                 const auto dur_secs = duration_cast<seconds>(remaining_dur);
240ee1f578dSGreg Clayton                 const auto dur_usecs = remaining_dur % seconds(1);
241ee1f578dSGreg Clayton                 tv.tv_sec = dur_secs.count();
242ee1f578dSGreg Clayton                 tv.tv_usec = dur_usecs.count();
243ee1f578dSGreg Clayton             }
244ee1f578dSGreg Clayton             else
245ee1f578dSGreg Clayton             {
246ee1f578dSGreg Clayton                 // Just poll once with no timeout
247ee1f578dSGreg Clayton                 tv.tv_sec = 0;
248ee1f578dSGreg Clayton                 tv.tv_usec = 0;
249ee1f578dSGreg Clayton             }
250ee1f578dSGreg Clayton         }
251ee1f578dSGreg Clayton         const int num_set_fds = ::select(nfds, read_fdset_ptr, write_fdset_ptr, error_fdset_ptr, tv_ptr);
252ee1f578dSGreg Clayton         if (num_set_fds < 0)
253ee1f578dSGreg Clayton         {
254ee1f578dSGreg Clayton             // We got an error
255ee1f578dSGreg Clayton             error.SetErrorToErrno();
256ee1f578dSGreg Clayton             if (error.GetError() == EINTR)
257ee1f578dSGreg Clayton             {
258ee1f578dSGreg Clayton                 error.Clear();
259ee1f578dSGreg Clayton                 continue; // Keep calling select if we get EINTR
260ee1f578dSGreg Clayton             }
261ee1f578dSGreg Clayton             else
262ee1f578dSGreg Clayton                 return error;
263ee1f578dSGreg Clayton         }
264ee1f578dSGreg Clayton         else if (num_set_fds == 0)
265ee1f578dSGreg Clayton         {
266ee1f578dSGreg Clayton             // Timeout
267ee1f578dSGreg Clayton             error.SetError(ETIMEDOUT, lldb::eErrorTypePOSIX);
268ee1f578dSGreg Clayton             error.SetErrorString("timed out");
269ee1f578dSGreg Clayton             return error;
270ee1f578dSGreg Clayton         }
271ee1f578dSGreg Clayton         else
272ee1f578dSGreg Clayton         {
273ee1f578dSGreg Clayton             // One or more descriptors were set, update the FDInfo::select_is_set mask
274ee1f578dSGreg Clayton             // so users can ask the SelectHelper class so clients can call one of:
275ee1f578dSGreg Clayton 
276ee1f578dSGreg Clayton             for (auto &pair : m_fd_map)
277ee1f578dSGreg Clayton             {
278ee1f578dSGreg Clayton                 const int fd = pair.first;
279ee1f578dSGreg Clayton 
280ee1f578dSGreg Clayton                 if (pair.second.read_set)
281ee1f578dSGreg Clayton                 {
282ee1f578dSGreg Clayton                     if (FD_ISSET(fd, read_fdset_ptr))
283ee1f578dSGreg Clayton                         pair.second.read_is_set = true;
284ee1f578dSGreg Clayton                 }
285ee1f578dSGreg Clayton                 if (pair.second.write_set)
286ee1f578dSGreg Clayton                 {
287ee1f578dSGreg Clayton                     if (FD_ISSET(fd, write_fdset_ptr))
288ee1f578dSGreg Clayton                         pair.second.write_is_set = true;
289ee1f578dSGreg Clayton                 }
290ee1f578dSGreg Clayton                 if (pair.second.error_set)
291ee1f578dSGreg Clayton                 {
292ee1f578dSGreg Clayton                     if (FD_ISSET(fd, error_fdset_ptr))
293ee1f578dSGreg Clayton                         pair.second.error_is_set = true;
294ee1f578dSGreg Clayton                 }
295ee1f578dSGreg Clayton             }
296ee1f578dSGreg Clayton             break;
297ee1f578dSGreg Clayton         }
298ee1f578dSGreg Clayton     }
299ee1f578dSGreg Clayton     return error;
300ee1f578dSGreg Clayton }
301