• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * fs/vfs/fs_poll.c
3  *
4  *   Copyright (C) 2008-2009, 2012-2019 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 "los_hwi.h"
41 #include "vfs_config.h"
42 #include "stdint.h"
43 #include "poll.h"
44 #include "assert.h"
45 #include "errno.h"
46 #include "vnode.h"
47 #include "stdlib.h"
48 #include "stdio.h"
49 #include "console.h"
50 #include "unistd.h"
51 #include "linux/wait.h"
52 #ifdef LOSCFG_NET_LWIP_SACK
53 #include "lwip/sockets.h"
54 #endif
55 #ifndef CONFIG_DISABLE_POLL
56 
57 /****************************************************************************
58  * Pre-processor Definitions
59  ****************************************************************************/
60 
61 #ifndef MSEC_PER_SEC
62 #define MSEC_PER_SEC        1000L
63 #endif
64 
65 #ifndef NSEC_PER_MSEC
66 #define NSEC_PER_MSEC    1000000L
67 #endif
68 
69 #define N_POLL_ITEMS 5
70 #define poll_semgive(sem) sem_post(sem)
71 
72 /****************************************************************************
73  * Data Structures & Macros
74  ****************************************************************************/
75 
76 typedef wait_queue_head_t * poll_wait_queue;
77 
78 typedef struct tag_poll_wait_node
79 {
80   LOS_DL_LIST queue_node;
81   pollevent_t key;
82   struct tag_poll_wait_entry *entry;
83   poll_wait_queue wait_queue;
84 } poll_wait_node;
85 
86 typedef struct tag_poll_wait_entry_table
87 {
88   struct tag_poll_wait_entry_table *next;
89   UINT32 index;
90   poll_wait_node items[N_POLL_ITEMS];
91 } poll_wait_entry_table;
92 
93 typedef struct tag_poll_wait_entry
94 {
95   bool add_queue_flag;
96   sem_t sem;
97   UINT32 inline_index;
98   poll_wait_node inline_items[N_POLL_ITEMS];
99   poll_wait_entry_table *table;
100 } poll_wait_entry;
101 
102 /****************************************************************************
103  * Private Functions
104  ****************************************************************************/
105 
106 /****************************************************************************
107  * Name: poll_semtake
108  ****************************************************************************/
109 
poll_semtake(sem_t * sem)110 static int poll_semtake(sem_t *sem)
111 {
112   /* Take the semaphore (perhaps waiting) */
113 
114   if (sem_wait(sem) < 0)
115     {
116       int err = get_errno();
117 
118       /* The only case that an error should occur here is if the wait were
119        * awakened by a signal.
120        */
121 
122       DEBUGASSERT(err == EINTR);
123       return -err;
124     }
125 
126   return OK;
127 }
128 
set_add_poll_wait_flag(poll_wait_head wait,bool add_queue_flag)129 static void set_add_poll_wait_flag(poll_wait_head wait, bool add_queue_flag)
130 {
131   wait->add_queue_flag = add_queue_flag;
132 }
133 
destroy_poll_wait(poll_wait_head wait)134 static int destroy_poll_wait(poll_wait_head wait)
135 {
136   unsigned int i;
137   unsigned long int_save;
138   poll_wait_node *wait_node = NULL;
139   poll_wait_entry_table *curr_table = NULL;
140 
141   for (i = 0; i < wait->inline_index; ++i)
142     {
143       wait_node = &wait->inline_items[i];
144       spin_lock_irqsave(&wait_node->wait_queue->lock, int_save);
145       LOS_ListDelete(&wait_node->queue_node);
146       spin_unlock_irqrestore(&wait_node->wait_queue->lock, int_save);
147     }
148 
149   while (wait->table)
150     {
151       curr_table = wait->table;
152       wait->table = curr_table->next;
153 
154       for (i = 0; i < curr_table->index; ++i)
155         {
156           wait_node = &curr_table->items[i];
157           spin_lock_irqsave(&wait_node->wait_queue->lock, int_save);
158           LOS_ListDelete(&wait_node->queue_node);
159           spin_unlock_irqrestore(&wait_node->wait_queue->lock, int_save);
160         }
161       free(curr_table);
162     }
163 
164   if (sem_destroy(&wait->sem) < 0)
165     {
166       PRINT_ERR("[%s] sem_destroy failed\n", __FUNCTION__);
167       return -1;
168     }
169 
170   return 0;
171 }
172 
get_poll_item(poll_wait_head wait)173 static poll_wait_node *get_poll_item(poll_wait_head wait)
174 {
175   if (wait->inline_index < N_POLL_ITEMS)
176     {
177       return wait->inline_items + wait->inline_index++;
178     }
179   if (!wait->table || (wait->table && wait->table->index >= N_POLL_ITEMS))
180     {
181       poll_wait_entry_table *new_entry_table = NULL;
182 
183       new_entry_table = (poll_wait_entry_table *)malloc(sizeof(poll_wait_entry_table));
184       if (new_entry_table == NULL)
185         {
186           return (poll_wait_node *)NULL;
187         }
188       new_entry_table->index = 0;
189 
190       new_entry_table->next = wait->table;
191       wait->table = new_entry_table;
192     }
193 
194   return wait->table->items + wait->table->index++;
195 }
196 
add_pollwait_queue(poll_wait_queue queue,poll_table * p)197 static void add_pollwait_queue(poll_wait_queue queue, poll_table *p)
198 {
199   unsigned long int_save;
200   poll_wait_head wait = p->wait;
201   poll_wait_node *new_node = get_poll_item(wait);
202   if (new_node != NULL)
203     {
204       new_node->entry = wait;
205       new_node->key = p->key;
206       new_node->wait_queue = queue;
207       spin_lock_irqsave(&queue->lock, int_save);
208       LOS_ListAdd(&queue->poll_queue, &new_node->queue_node);
209       spin_unlock_irqrestore(&queue->lock, int_save);
210     }
211 }
212 
wait_sem_time(poll_wait_head wait,const struct timespec * time_ptr)213 static int wait_sem_time(poll_wait_head wait, const struct timespec *time_ptr)
214 {
215   if (time_ptr != NULL)
216     {
217       return sem_timedwait(&wait->sem, time_ptr);
218     }
219   else
220     {
221       return poll_semtake(&wait->sem);
222     }
223 }
224 
file_poll(struct file * filep,poll_table * wait)225 static int file_poll(struct file *filep, poll_table *wait)
226 {
227   int ret = -ENOSYS;
228 
229   if (filep->ops != NULL && filep->ops->poll != NULL)
230     {
231       ret = filep->ops->poll(filep, wait);
232     }
233 
234   return ret;
235 }
236 
fdesc_poll(int fd,poll_table * wait)237 static int fdesc_poll(int fd, poll_table *wait)
238 {
239   struct file *filep = NULL;
240 
241   if (fd <= STDERR_FILENO && fd >= STDIN_FILENO) /* fd : [0,2] */
242     {
243       fd = ConsoleUpdateFd();
244       if (fd < 0)
245         {
246           set_errno(EBADF);
247           return VFS_ERROR;
248         }
249     }
250 
251   /* Get the file pointer corresponding to this file descriptor */
252 
253   int ret = fs_getfilep(fd, &filep);
254   if (ret < 0)
255     {
256       /* The errno value has already been set */
257       int errorcode = get_errno();
258       return -errorcode;
259     }
260 
261   /* Let file_poll() do the rest */
262 
263   return file_poll(filep, wait);
264 }
265 
query_fd(int fd,poll_table * wait)266 static int query_fd(int fd, poll_table *wait)
267 {
268   /* Check for a valid file descriptor */
269 
270   if (fd >= CONFIG_NFILE_DESCRIPTORS)
271     {
272       /* Perform the socket ioctl */
273 
274 #if defined(LOSCFG_NET_LWIP_SACK)
275       if (fd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS))
276         {
277           return socks_poll(fd, wait);
278         }
279       else
280 #endif
281         {
282           return -EBADF;
283         }
284     }
285 
286   return fdesc_poll(fd, wait);
287 }
288 
query_fds(struct pollfd * fds,nfds_t nfds,poll_table * wait)289 static int query_fds(struct pollfd *fds, nfds_t nfds, poll_table *wait)
290 {
291   unsigned int i;
292   int ret;
293   int count = 0;
294 
295   if ((nfds != 0 && fds == NULL) || wait == NULL || wait->wait == NULL)
296     {
297       set_errno(EINVAL);
298       return -1;
299     }
300 
301   for (i = 0; i < nfds; ++i)
302     {
303       struct pollfd *p_fds = &fds[i];
304       if (p_fds->fd < 0)
305         {
306           set_errno(EBADF);
307           return -1;
308         }
309 
310       wait->key = p_fds->events | POLLERR | POLLHUP;
311 
312       ret = query_fd(p_fds->fd, wait);
313       if (ret < 0)
314         {
315           set_errno(-ret);
316           return -1;
317         }
318 
319       p_fds->revents = (p_fds->events | POLLERR | POLLHUP) & (pollevent_t)ret;
320       if (p_fds->revents)
321         {
322           ++count;
323           set_add_poll_wait_flag(wait->wait, false);
324         }
325     }
326 
327   return count;
328 }
329 
330 /****************************************************************************
331  * Public Functions
332  ****************************************************************************/
333 
notify_poll_with_key(wait_queue_head_t * wait_address,pollevent_t key)334 void notify_poll_with_key(wait_queue_head_t *wait_address, pollevent_t key)
335 {
336   unsigned long int_save;
337   int failed_count = 0;
338   poll_wait_node *curr = NULL;
339 
340   spin_lock_irqsave(&wait_address->lock, int_save);
341   LOS_DL_LIST_FOR_EACH_ENTRY(curr, &(wait_address->poll_queue), poll_wait_node, queue_node)
342     {
343       poll_wait_entry *curr_entry = curr->entry;
344       if (!key || (key & curr->key))
345         {
346           if (poll_semgive(&curr_entry->sem) < 0)
347             {
348               failed_count++;
349             }
350         }
351     }
352   spin_unlock_irqrestore(&wait_address->lock, int_save);
353 
354   if (failed_count != 0)
355     {
356       PRINT_ERR("[%s] sem_post failed %d times\n", __FUNCTION__, failed_count);
357     }
358 }
359 
360 /* just for compatible */
361 
notify_poll(wait_queue_head_t * wait_address)362 void notify_poll(wait_queue_head_t *wait_address)
363 {
364   notify_poll_with_key(wait_address, 0);
365 }
366 
poll_wait(struct file * filp,wait_queue_head_t * wait_address,poll_table * p)367 void poll_wait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p)
368 {
369   if (!wait_address || !p || !p->wait)
370     {
371       return;
372     }
373 
374   if (p->wait->add_queue_flag)
375     {
376       add_pollwait_queue(wait_address, p);
377     }
378 }
379 
380 /****************************************************************************
381  * Name: poll
382  *
383  * Description:
384  *   poll() waits for one of a set of file descriptors to become ready to
385  *   perform I/O.  If none of the events requested (and no error) has
386  *   occurred for any of  the  file  descriptors,  then  poll() blocks until
387  *   one of the events occurs.
388  *
389  * Input Parameters:
390  *   fds  - List of structures describing file descriptors to be monitored
391  *   nfds - The number of entries in the list
392  *   timeout - Specifies an upper limit on the time for which poll() will
393  *     block in milliseconds.  A negative value of timeout means an infinite
394  *     timeout.
395  *
396  * Returned Value:
397  *   On success, the number of structures that have non-zero revents fields.
398  *   A value of 0 indicates that the call timed out and no file descriptors
399  *   were ready.  On error, -1 is returned, and errno is set appropriately:
400  *
401  *   EBADF  - An invalid file descriptor was given in one of the sets.
402  *   EFAULT - The fds address is invalid
403  *   EINTR  - A signal occurred before any requested event.
404  *   EINVAL - The nfds value exceeds a system limit.
405  *   ENOMEM - There was no space to allocate internal data structures.
406  *   ENOSYS - One or more of the drivers supporting the file descriptor
407  *     does not support the poll method.
408  *
409  ****************************************************************************/
410 
poll(struct pollfd * fds,nfds_t nfds,int timeout)411 int poll(struct pollfd *fds, nfds_t nfds, int timeout)
412 {
413   poll_table wait_table;
414   poll_wait_entry wait_entry;
415   size_t start_ticks = 0;
416   int millisecs_left;
417   int ret = OK;
418   int count = 0;
419   int err = 0;
420   int temp = 0;
421 
422   wait_table.wait = &wait_entry;
423   wait_table.wait->table = NULL;
424   wait_table.wait->inline_index = 0;
425   if (sem_init(&wait_table.wait->sem, 0, 0) < 0)
426     {
427       set_errno(ENOMEM);
428       return -1;
429     }
430 
431   /* set wait flag */
432 
433   set_add_poll_wait_flag(wait_table.wait, ((timeout == 0) ? false : true));
434 
435   count = query_fds(fds, nfds, &wait_table);
436   if (count > 0)
437     {
438       ret = OK;
439       goto out;
440     }
441   else if (count < 0)
442     {
443       goto out;
444     }
445 
446   /* clear wait flag if no fd got on first query */
447 
448   set_add_poll_wait_flag(wait_table.wait, false);
449 
450   if (timeout > 0)
451     {
452       start_ticks = LOS_TickCountGet();
453     }
454 
455   millisecs_left = timeout;
456   while (count == 0)
457     {
458       if (timeout < 0)
459         {
460           ret = wait_sem_time(wait_table.wait, (const struct timespec *)NULL);
461         }
462       else if (timeout == 0 || millisecs_left <= 0)
463         {
464           ret = OK;
465           goto out;
466         }
467       else if (millisecs_left > 0)
468         {
469           struct timespec wait_time;
470           UINT64 curr_ticks;
471           int millisecs_last;
472 
473           curr_ticks = LOS_TickCountGet();
474           millisecs_last = (curr_ticks - start_ticks) * MSEC_PER_SEC / LOSCFG_BASE_CORE_TICK_PER_SECOND;
475           if (millisecs_last >= timeout)
476             {
477               ret = OK;
478               goto out;
479             }
480           else
481             {
482               millisecs_left = timeout - millisecs_last;
483             }
484 
485           wait_time.tv_sec  = millisecs_left / MSEC_PER_SEC;
486           wait_time.tv_nsec = (millisecs_left - MSEC_PER_SEC * wait_time.tv_sec) * NSEC_PER_MSEC;
487 
488           ret = wait_sem_time(wait_table.wait, &wait_time);
489           if (ret < 0)
490             {
491               err = get_errno();
492 
493               if (err == ETIMEDOUT)
494                 {
495                   ret = OK;
496                 }
497               else
498                 {
499                   ret = -err;
500                 }
501             }
502         }
503 
504       if (ret < 0)
505         {
506           goto out;
507         }
508       count = query_fds(fds, nfds, &wait_table);
509       if (err == ETIMEDOUT)
510         {
511           break;
512         }
513     }
514 
515 out:
516   temp = get_errno();
517   if (destroy_poll_wait(wait_table.wait) < 0)
518     {
519       temp = get_errno();
520     }
521 
522   if (temp != 0)
523     {
524       set_errno(temp);
525     }
526   if (ret < 0)
527     {
528       set_errno(-ret);
529       return -1;
530     }
531 
532   return count;
533 }
534 
535 #endif /* CONFIG_DISABLE_POLL */
536