• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * fs/vfs/fs_select.c
3  *
4  *   Copyright (C) 2008-2009, 2012-2013 Gregory Nutt. All rights reserved.
5  *   Author: Gregory Nutt <gnutt@nuttx.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name NuttX nor the names of its contributors may be
18  *    used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  ****************************************************************************/
35 
36 /****************************************************************************
37  * Included Files
38  ****************************************************************************/
39 
40 #include "vfs_config.h"
41 
42 #include "sys/select.h"
43 
44 #include "string.h"
45 #include "unistd.h"
46 #include "poll.h"
47 #include "assert.h"
48 #include "errno.h"
49 
50 #include "stdlib.h"
51 
52 #include "los_signal.h"
53 #include "los_syscall.h"
54 
55 #ifndef CONFIG_DISABLE_POLL
56 
57 
58 /****************************************************************************
59  * Pre-processor Definitions
60  ****************************************************************************/
61 
62 #define POLL_IN_SET (POLLIN | POLLRDNORM | POLLRDBAND | POLLHUP | POLLERR)
63 #define POLL_OUT_SET (POLLOUT | POLLWRBAND | POLLWRNORM | POLLERR)
64 #define POLL_EX_SET (POLLPRI)
65 
66 /* pollfd count in stack, optimization in order to avoid small memory allocation */
67 
68 #define POLL_STACK_CNT 5
69 
70 /****************************************************************************
71  * Private Functions
72  ****************************************************************************/
73 
74 /****************************************************************************
75  * Public Functions
76  ****************************************************************************/
77 extern unsigned int sleep(unsigned int seconds);
78 
79 /****************************************************************************
80  * Name: select
81  *
82  * Description:
83  *   select() allows a program to monitor multiple file descriptors, waiting
84  *   until one or more of the file descriptors become "ready" for some class
85  *   of I/O operation (e.g., input possible).  A file descriptor is
86  *   considered  ready if it is possible to perform the corresponding I/O
87  *   operation (e.g., read(2)) without blocking.
88  *
89  *   NOTE: poll() is the fundamental API for performing such monitoring
90  *   operation under NuttX.  select() is provided for compatibility and
91  *   is simply a layer of added logic on top of poll().  As such, select()
92  *   is more wasteful of resources and poll() is the recommended API to be
93  *   used.
94  *
95  * Input Parameters:
96  *   nfds - the maximum fd number (+1) of any descriptor in any of the
97  *     three sets.
98  *   readfds - the set of descriptions to monitor for read-ready events
99  *   writefds - the set of descriptions to monitor for write-ready events
100  *   exceptfds - the set of descriptions to monitor for error events
101  *   timeout - Return at this time if none of these events of interest
102  *     occur.
103  *
104  *  Returned Value:
105  *   0: Timer expired
106  *  >0: The number of bits set in the three sets of descriptors
107  *  -1: An error occurred (errno will be set appropriately)
108  *
109  ****************************************************************************/
110 
do_select(int nfds,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout,PollFun poll)111 int do_select(int nfds, fd_set *readfds, fd_set *writefds,
112            fd_set *exceptfds, struct timeval *timeout, PollFun poll)
113 {
114   struct pollfd *pollset = NULL;
115   struct pollfd pfd[POLL_STACK_CNT];
116   int pfd_alloc_flag = 0;
117   int fd;
118   int npfds;
119   int msec;
120   int ndx;
121   int ret;
122 
123   if (nfds < 0)
124     {
125       set_errno(EINVAL);
126       return VFS_ERROR;
127     }
128 
129   /* How many pollfd structures do we need to allocate? */
130 
131   /* Initialize the descriptor list for poll() */
132 
133   for (fd = 0, npfds = 0; fd < nfds; fd++)
134     {
135       /* Check if any monitor operation is requested on this fd */
136 
137       if ((readfds   && FD_ISSET(fd, readfds))  ||
138           (writefds  && FD_ISSET(fd, writefds)) ||
139           (exceptfds && FD_ISSET(fd, exceptfds)))
140         {
141           /* Yes.. increment the count of pollfds structures needed */
142 
143           npfds++;
144         }
145     }
146 
147   /* Allocate the descriptor list for poll() */
148 
149   if (npfds != 0)
150     {
151       /* use stack variable in order to avoid small memory allocation. */
152 
153       if (npfds <= POLL_STACK_CNT)
154         {
155           pollset = pfd;
156           (void)memset_s(pollset, npfds * sizeof(struct pollfd), 0, npfds * sizeof(struct pollfd));
157         }
158       else
159         {
160           pollset = (struct pollfd *)zalloc(npfds * sizeof(struct pollfd));
161           if (pollset == NULL)
162             {
163               set_errno(ENOMEM);
164               return VFS_ERROR;
165             }
166           pfd_alloc_flag = 1;
167         }
168     }
169   else
170     {
171       /* If the readfds, writefds, and exceptfds arguments are all null pointers and
172        * the timeout argument is not a null pointer, the select() function shall block for
173        * the time specified. If the readfds, writefds, and exceptfds arguments are all
174        * null pointers and the timeout argument is a null pointer, this is NOT permitted
175        * as LiteOS doesn't support Signal machanism, so select() can't come back anymore.
176        */
177 
178       if (timeout != NULL)
179         {
180           /* 1000000 : Convert seconds to microseconds. */
181 
182           if ((long long)timeout->tv_sec * 1000000 > 0xffffffff)
183             {
184               (void)sleep(timeout->tv_sec);
185             }
186           else
187             {
188               (void)usleep(timeout->tv_sec * 1000000 + timeout->tv_usec);
189             }
190           return OK;
191         }
192       else
193         {
194           set_errno(EINVAL);
195           return VFS_ERROR;
196         }
197     }
198 
199   /* Initialize the descriptor list for poll() */
200 
201   for (fd = 0, ndx = 0; fd < nfds; fd++)
202     {
203       int incr = 0;
204 
205       /* The readfs set holds the set of FDs that the caller can be assured
206        * of reading from without blocking.  Note that POLLHUP is included as
207        * a read-able condition.  POLLHUP will be reported at the end-of-file
208        * or when a connection is lost.  In either case, the read() can then
209        * be performed without blocking.
210        */
211 
212       if (readfds && FD_ISSET(fd, readfds))
213         {
214           pollset[ndx].fd = fd;
215           pollset[ndx].events |= (POLLIN | POLLRDNORM);
216           incr = 1;
217         }
218 
219       /* The writefds set holds the set of FDs that the caller can be assured
220        * of writing to without blocking.
221        */
222 
223       if (writefds && FD_ISSET(fd, writefds))
224         {
225           pollset[ndx].fd      = fd;
226           pollset[ndx].events |= (POLLOUT | POLLWRNORM);
227           incr                 = 1;
228         }
229 
230       /* The exceptfds set holds the set of FDs that are watched for exceptions */
231 
232       if (exceptfds && FD_ISSET(fd, exceptfds))
233         {
234           pollset[ndx].fd      = fd;
235           incr                  = 1;
236         }
237 
238       ndx += incr;
239     }
240 
241   DEBUGASSERT(ndx == npfds);
242 
243   /* Convert the timeout to milliseconds */
244 
245   if (timeout)
246     {
247       /* Calculate the timeout in milliseconds */
248 
249       msec = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
250     }
251   else
252     {
253       /* Any negative value of msec means no timeout */
254 
255       msec = -1;
256     }
257 
258   /* Then let poll do all of the real work. */
259 
260   ret = poll(pollset, npfds, msec);
261 
262   /* Now set up the return values */
263 
264   if (readfds)
265     {
266       (void)memset_s(readfds, sizeof(fd_set), 0, sizeof(fd_set));
267     }
268 
269   if (writefds)
270     {
271       (void)memset_s(writefds, sizeof(fd_set), 0, sizeof(fd_set));
272     }
273 
274   if (exceptfds)
275     {
276       (void)memset_s(exceptfds, sizeof(fd_set), 0, sizeof(fd_set));
277     }
278 
279   /* Convert the poll descriptor list back into selects 3 bitsets */
280 
281   if (ret > 0)
282     {
283       ret = 0;
284       for (ndx = 0; ndx < npfds; ndx++)
285         {
286           /* Check for read conditions.  Note that POLLHUP is included as a
287            * read condition.  POLLHUP will be reported when no more data will
288            * be available (such as when a connection is lost).  In either
289            * case, the read() can then be performed without blocking.
290            */
291 
292           if (readfds)
293             {
294               if (pollset[ndx].revents & POLL_IN_SET)
295                 {
296                   FD_SET(pollset[ndx].fd, readfds);
297                   ret++;
298                 }
299             }
300 
301           /* Check for write conditions */
302 
303           if (writefds)
304             {
305               if (pollset[ndx].revents & POLL_OUT_SET)
306                 {
307                   FD_SET(pollset[ndx].fd, writefds);
308                   ret++;
309                 }
310             }
311 
312           /* Check for exceptions */
313 
314           if (exceptfds)
315             {
316               if (pollset[ndx].revents & POLL_EX_SET)
317                 {
318                   FD_SET(pollset[ndx].fd, exceptfds);
319                   ret++;
320                 }
321             }
322         }
323     }
324 
325   if (pfd_alloc_flag)
326     {
327       free(pollset);
328     }
329   return ret;
330 }
331 
select(int nfds,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout)332 int select(int nfds, fd_set *readfds, fd_set *writefds,
333            fd_set *exceptfds, struct timeval *timeout)
334 {
335   return do_select(nfds, readfds, writefds, exceptfds, timeout, poll);
336 }
337 
338 #endif /* CONFIG_DISABLE_POLL */
339