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 "aos/kernel.h"
11 #include "aos/vfs.h"
12 #include <select.h>
13
14 #ifndef CONFIG_AOS_LWIP
15 #define CONFIG_NO_TCPIP
16 #endif
17
18 #ifdef CONFIG_NO_TCPIP
19 struct poll_arg {
20 aos_sem_t sem;
21 };
22
vfs_poll_notify(void * fd,void * arg)23 static void vfs_poll_notify(void *fd, void *arg)
24 {
25 struct poll_arg *parg = arg;
26 aos_sem_signal(&parg->sem);
27 }
28
wait_io(int maxfd,fd_set * rfds,fd_set * wfds,fd_set * efds,struct poll_arg * parg,int timeout)29 static int wait_io(int maxfd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct poll_arg *parg, int timeout)
30 {
31 timeout = timeout >= 0 ? timeout : AOS_WAIT_FOREVER;
32 aos_sem_wait(&parg->sem, timeout);
33 return 0;
34 }
35
init_parg(struct poll_arg * parg)36 static int init_parg(struct poll_arg *parg)
37 {
38 aos_sem_new(&parg->sem, 0);
39 return 0;
40 }
41
deinit_parg(struct poll_arg * parg)42 static void deinit_parg(struct poll_arg *parg)
43 {
44 aos_sem_free(&parg->sem);
45 }
46 #else
47 #include <sys/socket.h>
48 struct poll_arg {
49 int efd;
50 };
51
52 extern int lwip_write(int s, const void *dataptr, size_t size);
53 extern int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
54 struct timeval *timeout);
55 extern int lwip_eventfd(unsigned int initval, int flags);
56 extern int lwip_close(int s);
57
vfs_poll_notify(void * fd,void * arg)58 static void vfs_poll_notify(void *fd, void *arg)
59 {
60 struct poll_arg *parg = arg;
61 uint64_t val = 1;
62 lwip_write(parg->efd, &val, sizeof val);
63 }
64
init_parg(struct poll_arg * parg)65 static int init_parg(struct poll_arg *parg)
66 {
67 int efd;
68 efd = lwip_eventfd(0, 0);
69
70 if (efd < 0) {
71 errno = EINVAL;
72 return -1;
73 }
74
75 parg->efd = efd;
76
77 return 0;
78 }
79
deinit_parg(struct poll_arg * parg)80 static void deinit_parg(struct poll_arg *parg)
81 {
82 lwip_close(parg->efd);
83 }
84
wait_io(int maxfd,fd_set * rfds,fd_set * wfds,fd_set * efds,struct poll_arg * parg,int timeout)85 static int wait_io(int maxfd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct poll_arg *parg, int timeout)
86 {
87 int ret;
88 struct timeval tv = {
89 .tv_sec = timeout / 1000,
90 .tv_usec = (timeout % 1000) * 1000,
91 };
92
93 FD_SET(parg->efd, rfds);
94 maxfd = parg->efd > maxfd ? parg->efd : maxfd;
95 ret = lwip_select(maxfd + 1, rfds, wfds, efds, timeout >= 0 ? &tv : NULL);
96
97 /* return socketfd event num only ,so we sub event fd num */
98 if (ret > 0) {
99 if (FD_ISSET(parg->efd, rfds)) {
100 ret--;
101 }
102 if (FD_ISSET(parg->efd, wfds)) {
103 errno = EINVAL;
104 return -1;
105 }
106 if (FD_ISSET(parg->efd, efds)) {
107 errno = EINVAL;
108 return -1;
109 }
110 }
111 return ret;
112 }
113 #endif
114
pre_poll(struct pollfd * fds,int nfds,fd_set * rfds,fd_set * wfds,fd_set * efds,void * parg)115 static int pre_poll(struct pollfd *fds, int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, void *parg)
116 {
117 int i;
118 int maxfd = 0;
119
120 for (i = 0; i < nfds; i++) {
121 struct pollfd *pfd = &fds[i];
122
123 pfd->revents = 0;
124 }
125
126 for (i = 0; i < nfds; i++) {
127 struct pollfd *pfd = &fds[i];
128 if (pfd->fd < aos_vfs_fd_offset_get()) {
129 if (pfd->fd > FD_SETSIZE - 1) {
130 errno = EINVAL;
131 return -1;
132 }
133 if (pfd->events & POLLIN) {
134 FD_SET(pfd->fd, rfds);
135 }
136 if (pfd->events & POLLOUT) {
137 FD_SET(pfd->fd, wfds);
138 }
139 if (pfd->events & POLLERR) {
140 FD_SET(pfd->fd, efds);
141 }
142 maxfd = pfd->fd > maxfd ? pfd->fd : maxfd;
143 } else {
144 if (aos_do_pollfd(pfd->fd, true, vfs_poll_notify, pfd, parg) == -ENOENT) {
145 errno = ENOENT;
146 return -1;
147 }
148 }
149 }
150
151 return maxfd;
152 }
153
post_poll(struct pollfd * fds,int nfds)154 static int post_poll(struct pollfd *fds, int nfds)
155 {
156 int j;
157 int ret = 0;
158
159 for (j = 0; j < nfds; j++) {
160 struct pollfd *pfd = &fds[j];
161
162 if (pfd->fd < aos_vfs_fd_offset_get()) {
163 continue;
164 }
165
166 if (aos_do_pollfd(pfd->fd, false, NULL, NULL, NULL) == -ENOENT) {
167 continue;
168 }
169
170 if (pfd->revents) {
171 ret ++;
172 }
173 }
174
175 return ret;
176 }
177
aos_poll(struct pollfd * fds,int nfds,int timeout)178 int aos_poll(struct pollfd *fds, int nfds, int timeout)
179 {
180 fd_set rfds;
181 fd_set wfds;
182 fd_set efds;
183
184 int ret = 0;
185 int nset = 0;
186 struct poll_arg parg;
187
188 if (init_parg(&parg) < 0) {
189 return -1;
190 }
191
192 FD_ZERO(&rfds);
193 FD_ZERO(&wfds);
194 FD_ZERO(&efds);
195
196 ret = pre_poll(fds, nfds, &rfds, &wfds, &efds, &parg);
197
198 if (ret < 0) {
199 goto check_poll;
200 }
201
202 ret = wait_io(ret, &rfds, &wfds, &efds, &parg, timeout);
203
204 if (ret > 0) {
205 int i;
206
207 for (i = 0; i < nfds; i++) {
208 struct pollfd *pfd = &fds[i];
209
210 if (FD_ISSET(pfd->fd, &rfds)) {
211 pfd->revents |= POLLIN;
212 }
213 if (FD_ISSET(pfd->fd, &wfds)) {
214 pfd->revents |= POLLOUT;
215 }
216 if (FD_ISSET(pfd->fd, &efds)) {
217 pfd->revents |= POLLERR;
218 }
219 }
220 nset += ret;
221 }
222
223 check_poll:
224 nset += post_poll(fds, nfds);
225
226 deinit_parg(&parg);
227
228 return ret < 0 ? -1 : nset;
229 }
230