1*10465441SEvalZero /*
2*10465441SEvalZero * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero *
4*10465441SEvalZero * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero *
6*10465441SEvalZero * Change Logs:
7*10465441SEvalZero * Date Author Notes
8*10465441SEvalZero * 2016-12-28 Bernard first version
9*10465441SEvalZero * 2018-03-09 Bernard Add protection for pt->triggered.
10*10465441SEvalZero */
11*10465441SEvalZero #include <stdint.h>
12*10465441SEvalZero
13*10465441SEvalZero #include <rthw.h>
14*10465441SEvalZero #include <rtdevice.h>
15*10465441SEvalZero #include <rtthread.h>
16*10465441SEvalZero
17*10465441SEvalZero #include <dfs.h>
18*10465441SEvalZero #include <dfs_file.h>
19*10465441SEvalZero #include <dfs_posix.h>
20*10465441SEvalZero #include <dfs_poll.h>
21*10465441SEvalZero
22*10465441SEvalZero struct rt_poll_node;
23*10465441SEvalZero
24*10465441SEvalZero struct rt_poll_table
25*10465441SEvalZero {
26*10465441SEvalZero rt_pollreq_t req;
27*10465441SEvalZero rt_uint32_t triggered; /* the waited thread whether triggered */
28*10465441SEvalZero rt_thread_t polling_thread;
29*10465441SEvalZero struct rt_poll_node *nodes;
30*10465441SEvalZero };
31*10465441SEvalZero
32*10465441SEvalZero struct rt_poll_node
33*10465441SEvalZero {
34*10465441SEvalZero struct rt_wqueue_node wqn;
35*10465441SEvalZero struct rt_poll_table *pt;
36*10465441SEvalZero struct rt_poll_node *next;
37*10465441SEvalZero };
38*10465441SEvalZero
__wqueue_pollwake(struct rt_wqueue_node * wait,void * key)39*10465441SEvalZero static int __wqueue_pollwake(struct rt_wqueue_node *wait, void *key)
40*10465441SEvalZero {
41*10465441SEvalZero struct rt_poll_node *pn;
42*10465441SEvalZero
43*10465441SEvalZero if (key && !((rt_ubase_t)key & wait->key))
44*10465441SEvalZero return -1;
45*10465441SEvalZero
46*10465441SEvalZero pn = rt_container_of(wait, struct rt_poll_node, wqn);
47*10465441SEvalZero pn->pt->triggered = 1;
48*10465441SEvalZero
49*10465441SEvalZero return __wqueue_default_wake(wait, key);
50*10465441SEvalZero }
51*10465441SEvalZero
_poll_add(rt_wqueue_t * wq,rt_pollreq_t * req)52*10465441SEvalZero static void _poll_add(rt_wqueue_t *wq, rt_pollreq_t *req)
53*10465441SEvalZero {
54*10465441SEvalZero struct rt_poll_table *pt;
55*10465441SEvalZero struct rt_poll_node *node;
56*10465441SEvalZero
57*10465441SEvalZero node = rt_malloc(sizeof(struct rt_poll_node));
58*10465441SEvalZero if (node == RT_NULL)
59*10465441SEvalZero return;
60*10465441SEvalZero
61*10465441SEvalZero pt = rt_container_of(req, struct rt_poll_table, req);
62*10465441SEvalZero
63*10465441SEvalZero node->wqn.key = req->_key;
64*10465441SEvalZero rt_list_init(&(node->wqn.list));
65*10465441SEvalZero node->wqn.polling_thread = pt->polling_thread;
66*10465441SEvalZero node->wqn.wakeup = __wqueue_pollwake;
67*10465441SEvalZero node->next = pt->nodes;
68*10465441SEvalZero node->pt = pt;
69*10465441SEvalZero pt->nodes = node;
70*10465441SEvalZero rt_wqueue_add(wq, &node->wqn);
71*10465441SEvalZero }
72*10465441SEvalZero
poll_table_init(struct rt_poll_table * pt)73*10465441SEvalZero static void poll_table_init(struct rt_poll_table *pt)
74*10465441SEvalZero {
75*10465441SEvalZero pt->req._proc = _poll_add;
76*10465441SEvalZero pt->triggered = 0;
77*10465441SEvalZero pt->nodes = RT_NULL;
78*10465441SEvalZero pt->polling_thread = rt_thread_self();
79*10465441SEvalZero }
80*10465441SEvalZero
poll_wait_timeout(struct rt_poll_table * pt,int msec)81*10465441SEvalZero static int poll_wait_timeout(struct rt_poll_table *pt, int msec)
82*10465441SEvalZero {
83*10465441SEvalZero rt_int32_t timeout;
84*10465441SEvalZero int ret = 0;
85*10465441SEvalZero struct rt_thread *thread;
86*10465441SEvalZero rt_base_t level;
87*10465441SEvalZero
88*10465441SEvalZero thread = pt->polling_thread;
89*10465441SEvalZero
90*10465441SEvalZero timeout = rt_tick_from_millisecond(msec);
91*10465441SEvalZero
92*10465441SEvalZero level = rt_hw_interrupt_disable();
93*10465441SEvalZero
94*10465441SEvalZero if (timeout != 0 && !pt->triggered)
95*10465441SEvalZero {
96*10465441SEvalZero rt_thread_suspend(thread);
97*10465441SEvalZero if (timeout > 0)
98*10465441SEvalZero {
99*10465441SEvalZero rt_timer_control(&(thread->thread_timer),
100*10465441SEvalZero RT_TIMER_CTRL_SET_TIME,
101*10465441SEvalZero &timeout);
102*10465441SEvalZero rt_timer_start(&(thread->thread_timer));
103*10465441SEvalZero }
104*10465441SEvalZero
105*10465441SEvalZero rt_hw_interrupt_enable(level);
106*10465441SEvalZero
107*10465441SEvalZero rt_schedule();
108*10465441SEvalZero
109*10465441SEvalZero level = rt_hw_interrupt_disable();
110*10465441SEvalZero }
111*10465441SEvalZero
112*10465441SEvalZero ret = !pt->triggered;
113*10465441SEvalZero rt_hw_interrupt_enable(level);
114*10465441SEvalZero
115*10465441SEvalZero return ret;
116*10465441SEvalZero }
117*10465441SEvalZero
do_pollfd(struct pollfd * pollfd,rt_pollreq_t * req)118*10465441SEvalZero static int do_pollfd(struct pollfd *pollfd, rt_pollreq_t *req)
119*10465441SEvalZero {
120*10465441SEvalZero int mask = 0;
121*10465441SEvalZero int fd;
122*10465441SEvalZero
123*10465441SEvalZero fd = pollfd->fd;
124*10465441SEvalZero
125*10465441SEvalZero if (fd >= 0)
126*10465441SEvalZero {
127*10465441SEvalZero struct dfs_fd *f = fd_get(fd);
128*10465441SEvalZero mask = POLLNVAL;
129*10465441SEvalZero
130*10465441SEvalZero if (f)
131*10465441SEvalZero {
132*10465441SEvalZero mask = POLLMASK_DEFAULT;
133*10465441SEvalZero if (f->fops->poll)
134*10465441SEvalZero {
135*10465441SEvalZero req->_key = pollfd->events | POLLERR| POLLHUP;
136*10465441SEvalZero
137*10465441SEvalZero mask = f->fops->poll(f, req);
138*10465441SEvalZero }
139*10465441SEvalZero /* Mask out unneeded events. */
140*10465441SEvalZero mask &= pollfd->events | POLLERR | POLLHUP;
141*10465441SEvalZero fd_put(f);
142*10465441SEvalZero }
143*10465441SEvalZero }
144*10465441SEvalZero pollfd->revents = mask;
145*10465441SEvalZero
146*10465441SEvalZero return mask;
147*10465441SEvalZero }
148*10465441SEvalZero
poll_do(struct pollfd * fds,nfds_t nfds,struct rt_poll_table * pt,int msec)149*10465441SEvalZero static int poll_do(struct pollfd *fds, nfds_t nfds, struct rt_poll_table *pt, int msec)
150*10465441SEvalZero {
151*10465441SEvalZero int num;
152*10465441SEvalZero int istimeout = 0;
153*10465441SEvalZero int n;
154*10465441SEvalZero struct pollfd *pf;
155*10465441SEvalZero
156*10465441SEvalZero if (msec == 0)
157*10465441SEvalZero {
158*10465441SEvalZero pt->req._proc = RT_NULL;
159*10465441SEvalZero istimeout = 1;
160*10465441SEvalZero }
161*10465441SEvalZero
162*10465441SEvalZero while (1)
163*10465441SEvalZero {
164*10465441SEvalZero pf = fds;
165*10465441SEvalZero num = 0;
166*10465441SEvalZero
167*10465441SEvalZero for (n = 0; n < nfds; n ++)
168*10465441SEvalZero {
169*10465441SEvalZero if (do_pollfd(pf, &pt->req))
170*10465441SEvalZero {
171*10465441SEvalZero num ++;
172*10465441SEvalZero pt->req._proc = RT_NULL;
173*10465441SEvalZero }
174*10465441SEvalZero pf ++;
175*10465441SEvalZero }
176*10465441SEvalZero
177*10465441SEvalZero pt->req._proc = RT_NULL;
178*10465441SEvalZero
179*10465441SEvalZero if (num || istimeout)
180*10465441SEvalZero break;
181*10465441SEvalZero
182*10465441SEvalZero if (poll_wait_timeout(pt, msec))
183*10465441SEvalZero istimeout = 1;
184*10465441SEvalZero }
185*10465441SEvalZero
186*10465441SEvalZero return num;
187*10465441SEvalZero }
188*10465441SEvalZero
poll_teardown(struct rt_poll_table * pt)189*10465441SEvalZero static void poll_teardown(struct rt_poll_table *pt)
190*10465441SEvalZero {
191*10465441SEvalZero struct rt_poll_node *node, *next;
192*10465441SEvalZero
193*10465441SEvalZero next = pt->nodes;
194*10465441SEvalZero while (next)
195*10465441SEvalZero {
196*10465441SEvalZero node = next;
197*10465441SEvalZero rt_wqueue_remove(&node->wqn);
198*10465441SEvalZero next = node->next;
199*10465441SEvalZero rt_free(node);
200*10465441SEvalZero }
201*10465441SEvalZero }
202*10465441SEvalZero
poll(struct pollfd * fds,nfds_t nfds,int timeout)203*10465441SEvalZero int poll(struct pollfd *fds, nfds_t nfds, int timeout)
204*10465441SEvalZero {
205*10465441SEvalZero int num;
206*10465441SEvalZero struct rt_poll_table table;
207*10465441SEvalZero
208*10465441SEvalZero poll_table_init(&table);
209*10465441SEvalZero
210*10465441SEvalZero num = poll_do(fds, nfds, &table, timeout);
211*10465441SEvalZero
212*10465441SEvalZero poll_teardown(&table);
213*10465441SEvalZero
214*10465441SEvalZero return num;
215*10465441SEvalZero }
216*10465441SEvalZero
217