1 /*
2 * Copyright (C) 2020-2021 Alibaba Group Holding Limited
3 */
4
5 #include <stdbool.h>
6 #include <stdio.h>
7 #include <limits.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <poll.h>
11 #include "aos/kernel.h"
12 #include "aos/vfs.h"
13 #include "aos/list.h"
14 #include "sys/socket.h"
15 #include <select.h>
16
17
18 #define WRITE_VAL 1
19
20 #ifndef CONFIG_AOS_LWIP
21 #define CONFIG_NO_TCPIP
22 #endif
23
24 typedef struct poll_node {
25 struct pollfd pfd;
26 dlist_t next;
27 } poll_node_t;
28
29 #ifdef CONFIG_NO_TCPIP
30
31 struct poll_arg {
32 aos_sem_t sem;
33 };
34
vfs_poll_notify(void * fd,void * arg)35 static void vfs_poll_notify(void *fd, void *arg)
36 {
37 struct poll_arg *parg = arg;
38 aos_sem_signal(&parg->sem);
39 }
40
41
init_parg(struct poll_arg * parg)42 static int init_parg(struct poll_arg *parg)
43 {
44 aos_sem_new(&parg->sem, 0);
45 return 0;
46 }
47
wait_io(int maxfd,fd_set * readset,fd_set * writeset,fd_set * exceptset,struct poll_arg * parg,struct timeval * timeout)48 static int wait_io(int maxfd, fd_set *readset, fd_set *writeset, fd_set *exceptset,
49 struct poll_arg *parg, struct timeval *timeout)
50 {
51 uint64_t ms = timeout ? (timeout->tv_sec * 1000 + timeout->tv_usec / 1000) : AOS_WAIT_FOREVER;
52 aos_sem_wait(&parg->sem, ms);
53 return 0;
54 }
55
deinit_parg(struct poll_arg * parg)56 static void deinit_parg(struct poll_arg *parg)
57 {
58 aos_sem_free(&parg->sem);
59 }
60 #else
61 #include <sys/socket.h>
62
63 extern int lwip_write(int s, const void *dataptr, size_t size);
64 extern int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
65 struct timeval *timeout);
66 extern int lwip_eventfd(unsigned int initval, int flags);
67 extern int lwip_close(int s);
68
69 struct poll_arg {
70 int efd;
71 };
72
vfs_poll_notify(void * fd,void * arg)73 static void vfs_poll_notify(void *fd, void *arg)
74 {
75 struct poll_arg *parg = arg;
76 uint64_t val = WRITE_VAL;
77 net_write(parg->efd, &val, sizeof val);
78 }
79
init_parg(struct poll_arg * parg)80 static int init_parg(struct poll_arg *parg)
81 {
82 int efd;
83 efd = net_eventfd(0, 0);
84 if (efd < 0) {
85 errno = EINVAL;
86 return -1;
87 }
88
89 parg->efd = efd;
90
91 return 0;
92 }
93
wait_io(int maxfd,fd_set * readset,fd_set * writeset,fd_set * exceptset,struct poll_arg * parg,struct timeval * timeout)94 static int wait_io(int maxfd, fd_set *readset, fd_set *writeset, fd_set *exceptset,
95 struct poll_arg *parg, struct timeval *timeout)
96 {
97 int ret = 0;
98 fd_set *real_rset = readset;
99 fd_set bk_rset;
100 if (readset == NULL) {
101 real_rset = &bk_rset;
102 memset(real_rset, 0, sizeof(fd_set));
103 }
104 FD_SET(parg->efd, real_rset);
105 maxfd = parg->efd > maxfd - 1 ? (parg->efd + 1) : maxfd;
106
107 ret = net_select(maxfd, real_rset, writeset, exceptset, timeout);
108 if (ret > 0) {
109 if (FD_ISSET(parg->efd, real_rset)) {
110 /*mask eventfd event to user*/
111 ret--;
112 }
113 }
114
115 FD_CLR(parg->efd, real_rset);
116 return ret;
117 }
118
deinit_parg(struct poll_arg * parg)119 static void deinit_parg(struct poll_arg *parg)
120 {
121 net_close(parg->efd);
122 }
123 #endif
pre_select(int fd,dlist_t * list,struct poll_arg * parg,fd_set * readset,fd_set * writeset,fd_set * exceptset)124 static int pre_select(int fd, dlist_t *list, struct poll_arg *parg, fd_set *readset, fd_set *writeset,
125 fd_set *exceptset)
126 {
127 poll_node_t *node;
128 struct pollfd *pfd = NULL;
129
130 if (readset != NULL && FD_ISSET(fd, readset)) {
131 if (fd < aos_vfs_fd_offset_get()) {
132 return 0;
133 }
134 node = aos_malloc(sizeof(poll_node_t));
135 if (node == NULL) {
136 errno = ENOMEM;
137 return -1;
138 }
139 memset(node, 0, sizeof(poll_node_t));
140
141 pfd = &node->pfd;
142 pfd->fd = fd;
143 pfd->events = POLLIN;
144 dlist_add(&node->next, list);
145 /* delete from socket select events */
146 FD_CLR(fd, readset);
147 if (aos_do_pollfd(fd, true, vfs_poll_notify, pfd, parg) == -ENOENT) {
148 return -1;
149 }
150 /* read\write\except event add one time only, so continue here */
151 return 0;
152 }
153
154 if (writeset != NULL && FD_ISSET(fd, writeset)) {
155 poll_node_t *node;
156 if (fd < aos_vfs_fd_offset_get()) {
157 return 0;
158 }
159 node = aos_malloc(sizeof(poll_node_t));
160 if (node == NULL) {
161 errno = ENOMEM;
162 return -1;
163 }
164 memset(node, 0, sizeof(poll_node_t));
165
166 pfd = &node->pfd;
167 pfd->fd = fd;
168 pfd->events = POLLOUT;
169 dlist_add(&node->next, list);
170 FD_CLR(fd, writeset);
171 if (aos_do_pollfd(fd, true, vfs_poll_notify, pfd, parg) == -ENOENT) {
172 return -1;
173 }
174 return 0;
175 }
176
177 if (exceptset != NULL && FD_ISSET(fd, exceptset)) {
178 poll_node_t *node;
179 if (fd < aos_vfs_fd_offset_get()) {
180 return 0;
181 }
182 node = aos_malloc(sizeof(poll_node_t));
183 if (node == NULL) {
184 errno = ENOMEM;
185 return -1;
186 }
187 memset(node, 0, sizeof(poll_node_t));
188
189 pfd = &node->pfd;
190 pfd->fd = fd;
191 pfd->events = POLLERR;
192 dlist_add(&node->next, list);
193 FD_CLR(fd, exceptset);
194 if (aos_do_pollfd(fd, true, vfs_poll_notify, pfd, parg) == -ENOENT) {
195 errno = ENOENT;
196 return -1;
197 }
198 return 0;
199 }
200 return 0;
201 }
202
post_select(dlist_t * list,fd_set * readset,fd_set * writeset,fd_set * exceptset)203 static int post_select(dlist_t *list, fd_set *readset, fd_set *writeset, fd_set *exceptset)
204 {
205 int ret = 0;
206 dlist_t *temp;
207 poll_node_t *node;
208
209 dlist_for_each_entry_safe(list, temp, node, poll_node_t, next) {
210
211 struct pollfd *pfd = &node->pfd;
212
213 if (pfd->fd < aos_vfs_fd_offset_get()) {
214 continue;
215 }
216 /* unregister vfs event */
217 if (aos_do_pollfd(pfd->fd, false, NULL, NULL, NULL) == -ENOENT) {
218 continue;
219 }
220
221 /* change poll event to select event */
222 if ((pfd->revents & POLLIN) && (readset != NULL)) {
223 FD_SET(pfd->fd, readset);
224 ret ++;
225 }
226
227 if ((pfd->revents & POLLOUT) && (writeset != NULL)) {
228 FD_SET(pfd->fd, writeset);
229 ret ++;
230 }
231
232 if ((pfd->revents & POLLERR) && (exceptset != NULL)) {
233 FD_SET(pfd->fd, exceptset);
234 ret ++;
235 }
236 }
237 return ret;
238 }
239
aos_select(int maxfd,fd_set * readset,fd_set * writeset,fd_set * exceptset,struct timeval * timeout)240 int aos_select(int maxfd, fd_set *readset, fd_set *writeset, fd_set *exceptset,
241 struct timeval *timeout)
242 {
243 int i;
244 int ret = -1;
245 int nset = 0;
246 struct poll_arg parg;
247 dlist_t *temp;
248 poll_node_t *node;
249 dlist_t vfs_list;
250
251 dlist_init(&vfs_list);
252
253 if (init_parg(&parg) < 0) {
254 goto err;
255 }
256
257 for (i = 0; i < maxfd; i++) {
258 if (pre_select(i, &vfs_list, &parg, readset, writeset, exceptset) < 0) {
259 deinit_parg(&parg);
260 goto err;
261 }
262 }
263
264 ret = wait_io(maxfd, readset, writeset, exceptset, &parg, timeout);
265
266 nset = ret + post_select(&vfs_list, readset, writeset, exceptset);
267
268 deinit_parg(&parg);
269 err:
270 dlist_for_each_entry_safe(&vfs_list, temp, node, poll_node_t, next) {
271 dlist_del(&node->next);
272 aos_free(node);
273 }
274
275 return ret < 0 ? -1 : nset;
276 }
277