1 /****************************************************************************
2 * fs/vfs/fs_select.c
3 *
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership. The
7 * ASF licenses this file to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance with the
9 * License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16 * License for the specific language governing permissions and limitations
17 * under the License.
18 *
19 ****************************************************************************/
20
21 /****************************************************************************
22 * Included Files
23 ****************************************************************************/
24
25 #include "vfs_config.h"
26
27 #include "sys/select.h"
28
29 #include "string.h"
30 #include "unistd.h"
31 #include "poll.h"
32 #include "assert.h"
33 #include "errno.h"
34
35 #include "stdlib.h"
36
37 #include "los_signal.h"
38 #include "los_syscall.h"
39
40 #ifndef CONFIG_DISABLE_POLL
41
42
43 /****************************************************************************
44 * Pre-processor Definitions
45 ****************************************************************************/
46
47 #define POLL_IN_SET (POLLIN | POLLRDNORM | POLLRDBAND | POLLHUP | POLLERR)
48 #define POLL_OUT_SET (POLLOUT | POLLWRBAND | POLLWRNORM | POLLERR)
49 #define POLL_EX_SET (POLLPRI)
50
51 /* pollfd count in stack, optimization in order to avoid small memory allocation */
52
53 #define POLL_STACK_CNT 5
54
55 /****************************************************************************
56 * Private Functions
57 ****************************************************************************/
58
59 /****************************************************************************
60 * Public Functions
61 ****************************************************************************/
62 extern unsigned int sleep(unsigned int seconds);
63
64 /****************************************************************************
65 * Name: select
66 *
67 * Description:
68 * select() allows a program to monitor multiple file descriptors, waiting
69 * until one or more of the file descriptors become "ready" for some class
70 * of I/O operation (e.g., input possible). A file descriptor is
71 * considered ready if it is possible to perform the corresponding I/O
72 * operation (e.g., read(2)) without blocking.
73 *
74 * NOTE: poll() is the fundamental API for performing such monitoring
75 * operation under NuttX. select() is provided for compatibility and
76 * is simply a layer of added logic on top of poll(). As such, select()
77 * is more wasteful of resources and poll() is the recommended API to be
78 * used.
79 *
80 * Input Parameters:
81 * nfds - the maximum fd number (+1) of any descriptor in any of the
82 * three sets.
83 * readfds - the set of descriptions to monitor for read-ready events
84 * writefds - the set of descriptions to monitor for write-ready events
85 * exceptfds - the set of descriptions to monitor for error events
86 * timeout - Return at this time if none of these events of interest
87 * occur.
88 *
89 * Returned Value:
90 * 0: Timer expired
91 * >0: The number of bits set in the three sets of descriptors
92 * -1: An error occurred (errno will be set appropriately)
93 *
94 ****************************************************************************/
95
do_select(int nfds,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout,PollFun poll)96 int do_select(int nfds, fd_set *readfds, fd_set *writefds,
97 fd_set *exceptfds, struct timeval *timeout, PollFun poll)
98 {
99 struct pollfd *pollset = NULL;
100 struct pollfd pfd[POLL_STACK_CNT];
101 int pfd_alloc_flag = 0;
102 int fd;
103 int npfds;
104 int msec;
105 int ndx;
106 int ret;
107
108 if (nfds < 0 || nfds >= FD_SETSIZE)
109 {
110 set_errno(EINVAL);
111 return VFS_ERROR;
112 }
113
114 /* How many pollfd structures do we need to allocate? */
115
116 /* Initialize the descriptor list for poll() */
117
118 for (fd = 0, npfds = 0; fd < nfds; fd++)
119 {
120 /* Check if any monitor operation is requested on this fd */
121
122 if ((readfds && FD_ISSET(fd, readfds)) ||
123 (writefds && FD_ISSET(fd, writefds)) ||
124 (exceptfds && FD_ISSET(fd, exceptfds)))
125 {
126 /* Yes.. increment the count of pollfds structures needed */
127
128 npfds++;
129 }
130 }
131
132 /* Allocate the descriptor list for poll() */
133
134 if (npfds != 0)
135 {
136 /* use stack variable in order to avoid small memory allocation. */
137
138 if (npfds <= POLL_STACK_CNT)
139 {
140 pollset = pfd;
141 (void)memset_s(pollset, npfds * sizeof(struct pollfd), 0, npfds * sizeof(struct pollfd));
142 }
143 else
144 {
145 pollset = (struct pollfd *)zalloc(npfds * sizeof(struct pollfd));
146 if (pollset == NULL)
147 {
148 set_errno(ENOMEM);
149 return VFS_ERROR;
150 }
151 pfd_alloc_flag = 1;
152 }
153 }
154 else
155 {
156 /* If the readfds, writefds, and exceptfds arguments are all null pointers and
157 * the timeout argument is not a null pointer, the select() function shall block for
158 * the time specified. If the readfds, writefds, and exceptfds arguments are all
159 * null pointers and the timeout argument is a null pointer, this is NOT permitted
160 * as LiteOS doesn't support Signal machanism, so select() can't come back anymore.
161 */
162
163 if (timeout != NULL)
164 {
165 /* 1000000 : Convert seconds to microseconds. */
166
167 if ((long long)timeout->tv_sec * 1000000 > 0xffffffff)
168 {
169 (void)sleep(timeout->tv_sec);
170 }
171 else
172 {
173 (void)usleep(timeout->tv_sec * 1000000 + timeout->tv_usec);
174 }
175 return OK;
176 }
177 else
178 {
179 set_errno(EINVAL);
180 return VFS_ERROR;
181 }
182 }
183
184 /* Initialize the descriptor list for poll() */
185
186 for (fd = 0, ndx = 0; fd < nfds; fd++)
187 {
188 int incr = 0;
189
190 /* The readfs set holds the set of FDs that the caller can be assured
191 * of reading from without blocking. Note that POLLHUP is included as
192 * a read-able condition. POLLHUP will be reported at the end-of-file
193 * or when a connection is lost. In either case, the read() can then
194 * be performed without blocking.
195 */
196
197 if (readfds && FD_ISSET(fd, readfds))
198 {
199 pollset[ndx].fd = fd;
200 pollset[ndx].events |= (POLLIN | POLLRDNORM);
201 incr = 1;
202 }
203
204 /* The writefds set holds the set of FDs that the caller can be assured
205 * of writing to without blocking.
206 */
207
208 if (writefds && FD_ISSET(fd, writefds))
209 {
210 pollset[ndx].fd = fd;
211 pollset[ndx].events |= (POLLOUT | POLLWRNORM);
212 incr = 1;
213 }
214
215 /* The exceptfds set holds the set of FDs that are watched for exceptions */
216
217 if (exceptfds && FD_ISSET(fd, exceptfds))
218 {
219 pollset[ndx].fd = fd;
220 incr = 1;
221 }
222
223 ndx += incr;
224 }
225
226 DEBUGASSERT(ndx == npfds);
227
228 /* Convert the timeout to milliseconds */
229
230 if (timeout)
231 {
232 /* Calculate the timeout in milliseconds */
233
234 msec = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
235 }
236 else
237 {
238 /* Any negative value of msec means no timeout */
239
240 msec = -1;
241 }
242
243 /* Then let poll do all of the real work. */
244
245 ret = poll(pollset, npfds, msec);
246
247 /* Now set up the return values */
248
249 if (readfds)
250 {
251 (void)memset_s(readfds, sizeof(fd_set), 0, sizeof(fd_set));
252 }
253
254 if (writefds)
255 {
256 (void)memset_s(writefds, sizeof(fd_set), 0, sizeof(fd_set));
257 }
258
259 if (exceptfds)
260 {
261 (void)memset_s(exceptfds, sizeof(fd_set), 0, sizeof(fd_set));
262 }
263
264 /* Convert the poll descriptor list back into selects 3 bitsets */
265
266 if (ret > 0)
267 {
268 ret = 0;
269 for (ndx = 0; ndx < npfds; ndx++)
270 {
271 /* Check for read conditions. Note that POLLHUP is included as a
272 * read condition. POLLHUP will be reported when no more data will
273 * be available (such as when a connection is lost). In either
274 * case, the read() can then be performed without blocking.
275 */
276
277 if (readfds)
278 {
279 if (pollset[ndx].revents & POLL_IN_SET)
280 {
281 FD_SET(pollset[ndx].fd, readfds);
282 ret++;
283 }
284 }
285
286 /* Check for write conditions */
287
288 if (writefds)
289 {
290 if (pollset[ndx].revents & POLL_OUT_SET)
291 {
292 FD_SET(pollset[ndx].fd, writefds);
293 ret++;
294 }
295 }
296
297 /* Check for exceptions */
298
299 if (exceptfds)
300 {
301 if (pollset[ndx].revents & POLL_EX_SET)
302 {
303 FD_SET(pollset[ndx].fd, exceptfds);
304 ret++;
305 }
306 }
307 }
308 }
309
310 if (pfd_alloc_flag)
311 {
312 free(pollset);
313 }
314 return ret;
315 }
316
select(int nfds,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout)317 int select(int nfds, fd_set *readfds, fd_set *writefds,
318 fd_set *exceptfds, struct timeval *timeout)
319 {
320 return do_select(nfds, readfds, writefds, exceptfds, timeout, poll);
321 }
322
323 #endif /* CONFIG_DISABLE_POLL */
324