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