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