summaryrefslogtreecommitdiff
path: root/components/dfs/src/dfs_poll.c
diff options
context:
space:
mode:
Diffstat (limited to 'components/dfs/src/dfs_poll.c')
-rw-r--r--components/dfs/src/dfs_poll.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/components/dfs/src/dfs_poll.c b/components/dfs/src/dfs_poll.c
new file mode 100644
index 0000000000..607b3487be
--- /dev/null
+++ b/components/dfs/src/dfs_poll.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2016-12-28 Bernard first version
+ * 2018-03-09 Bernard Add protection for pt->triggered.
+ */
+#include <stdint.h>
+
+#include <rthw.h>
+#include <rtdevice.h>
+#include <rtthread.h>
+
+#include <dfs.h>
+#include <dfs_file.h>
+#include <dfs_posix.h>
+#include <poll.h>
+
+#ifdef RT_USING_POSIX
+
+struct rt_poll_node;
+
+struct rt_poll_table
+{
+ rt_pollreq_t req;
+ rt_uint32_t triggered; /* the waited thread whether triggered */
+ rt_thread_t polling_thread;
+ struct rt_poll_node *nodes;
+};
+
+struct rt_poll_node
+{
+ struct rt_wqueue_node wqn;
+ struct rt_poll_table *pt;
+ struct rt_poll_node *next;
+};
+
+static int __wqueue_pollwake(struct rt_wqueue_node *wait, void *key)
+{
+ struct rt_poll_node *pn;
+
+ if (key && !((rt_ubase_t)key & wait->key))
+ return -1;
+
+ pn = rt_container_of(wait, struct rt_poll_node, wqn);
+ pn->pt->triggered = 1;
+
+ return __wqueue_default_wake(wait, key);
+}
+
+static void _poll_add(rt_wqueue_t *wq, rt_pollreq_t *req)
+{
+ struct rt_poll_table *pt;
+ struct rt_poll_node *node;
+
+ node = (struct rt_poll_node *)rt_malloc(sizeof(struct rt_poll_node));
+ if (node == RT_NULL)
+ return;
+
+ pt = rt_container_of(req, struct rt_poll_table, req);
+
+ node->wqn.key = req->_key;
+ rt_list_init(&(node->wqn.list));
+ node->wqn.polling_thread = pt->polling_thread;
+ node->wqn.wakeup = __wqueue_pollwake;
+ node->next = pt->nodes;
+ node->pt = pt;
+ pt->nodes = node;
+ rt_wqueue_add(wq, &node->wqn);
+}
+
+static void poll_table_init(struct rt_poll_table *pt)
+{
+ pt->req._proc = _poll_add;
+ pt->triggered = 0;
+ pt->nodes = RT_NULL;
+ pt->polling_thread = rt_thread_self();
+}
+
+static int poll_wait_timeout(struct rt_poll_table *pt, int msec)
+{
+ rt_int32_t timeout;
+ int ret = 0;
+ struct rt_thread *thread;
+ rt_base_t level;
+
+ thread = pt->polling_thread;
+
+ timeout = rt_tick_from_millisecond(msec);
+
+ level = rt_hw_interrupt_disable();
+
+ if (timeout != 0 && !pt->triggered)
+ {
+ rt_thread_suspend(thread);
+ if (timeout > 0)
+ {
+ rt_timer_control(&(thread->thread_timer),
+ RT_TIMER_CTRL_SET_TIME,
+ &timeout);
+ rt_timer_start(&(thread->thread_timer));
+ }
+
+ rt_hw_interrupt_enable(level);
+
+ rt_schedule();
+
+ level = rt_hw_interrupt_disable();
+ }
+
+ ret = !pt->triggered;
+ rt_hw_interrupt_enable(level);
+
+ return ret;
+}
+
+static int do_pollfd(struct pollfd *pollfd, rt_pollreq_t *req)
+{
+ int mask = 0;
+ int fd;
+
+ fd = pollfd->fd;
+
+ if (fd >= 0)
+ {
+ struct dfs_fd *f = fd_get(fd);
+ mask = POLLNVAL;
+
+ if (f)
+ {
+ mask = POLLMASK_DEFAULT;
+ if (f->fops->poll)
+ {
+ req->_key = pollfd->events | POLLERR | POLLHUP;
+
+ mask = f->fops->poll(f, req);
+
+ /* dealwith the device return error -1*/
+ if (mask < 0)
+ {
+ fd_put(f);
+ pollfd->revents = 0;
+ return mask;
+ }
+ }
+ /* Mask out unneeded events. */
+ mask &= pollfd->events | POLLERR | POLLHUP;
+ fd_put(f);
+ }
+ }
+ pollfd->revents = mask;
+
+ return mask;
+}
+
+static int poll_do(struct pollfd *fds, nfds_t nfds, struct rt_poll_table *pt, int msec)
+{
+ int num;
+ int istimeout = 0;
+ int n;
+ struct pollfd *pf;
+ int ret = 0;
+
+ if (msec == 0)
+ {
+ pt->req._proc = RT_NULL;
+ istimeout = 1;
+ }
+
+ while (1)
+ {
+ pf = fds;
+ num = 0;
+
+ for (n = 0; n < nfds; n ++)
+ {
+ ret = do_pollfd(pf, &pt->req);
+ if(ret < 0)
+ {
+ /*dealwith the device return error -1 */
+ pt->req._proc = RT_NULL;
+ return ret;
+ }
+ else if(ret > 0)
+ {
+ num ++;
+ pt->req._proc = RT_NULL;
+ }
+ pf ++;
+ }
+
+ pt->req._proc = RT_NULL;
+
+ if (num || istimeout)
+ break;
+
+ if (poll_wait_timeout(pt, msec))
+ istimeout = 1;
+ }
+
+ return num;
+}
+
+static void poll_teardown(struct rt_poll_table *pt)
+{
+ struct rt_poll_node *node, *next;
+
+ next = pt->nodes;
+ while (next)
+ {
+ node = next;
+ rt_wqueue_remove(&node->wqn);
+ next = node->next;
+ rt_free(node);
+ }
+}
+
+int poll(struct pollfd *fds, nfds_t nfds, int timeout)
+{
+ int num;
+ struct rt_poll_table table;
+
+ poll_table_init(&table);
+
+ num = poll_do(fds, nfds, &table, timeout);
+
+ poll_teardown(&table);
+
+ return num;
+}
+
+#endif