1 // Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <stddef.h>
16 #include <sys/poll.h>
17 #include <sys/select.h>
18 #include <sys/errno.h>
19 #include <sys/param.h>
20 
poll(struct pollfd * fds,nfds_t nfds,int timeout)21 int poll(struct pollfd *fds, nfds_t nfds, int timeout)
22 {
23     struct timeval tv = {
24         // timeout is in milliseconds
25         .tv_sec = timeout / 1000,
26         .tv_usec = (timeout % 1000) * 1000,
27     };
28     int max_fd = -1;
29     fd_set readfds;
30     fd_set writefds;
31     fd_set errorfds;
32     struct _reent* r = __getreent();
33     int ret = 0;
34 
35     if (fds == NULL) {
36         __errno_r(r) = ENOENT;
37         return -1;
38     }
39 
40     FD_ZERO(&readfds);
41     FD_ZERO(&writefds);
42     FD_ZERO(&errorfds);
43 
44     for (unsigned int i = 0; i < nfds; ++i) {
45         fds[i].revents = 0;
46 
47         if (fds[i].fd < 0) {
48             // revents should remain 0 and events ignored (according to the documentation of poll()).
49             continue;
50         }
51 
52         if (fds[i].fd >= FD_SETSIZE) {
53             fds[i].revents |= POLLNVAL;
54             ++ret;
55             continue;
56         }
57 
58         if (fds[i].events & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
59             FD_SET(fds[i].fd, &readfds);
60             FD_SET(fds[i].fd, &errorfds);
61             max_fd = MAX(max_fd, fds[i].fd);
62         }
63 
64         if (fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
65             FD_SET(fds[i].fd, &writefds);
66             FD_SET(fds[i].fd, &errorfds);
67             max_fd = MAX(max_fd, fds[i].fd);
68         }
69     }
70 
71     const int select_ret = select(max_fd + 1, &readfds, &writefds, &errorfds, timeout < 0 ? NULL: &tv);
72 
73     if (select_ret > 0) {
74         ret += select_ret;
75 
76         for (unsigned int i = 0; i < nfds; ++i) {
77             if (FD_ISSET(fds[i].fd, &readfds)) {
78                 fds[i].revents |= POLLIN;
79             }
80 
81             if (FD_ISSET(fds[i].fd, &writefds)) {
82                 fds[i].revents |= POLLOUT;
83             }
84 
85             if (FD_ISSET(fds[i].fd, &errorfds)) {
86                 fds[i].revents |= POLLERR;
87             }
88         }
89     } else {
90         ret = select_ret;
91         // keeping the errno from select()
92     }
93 
94     return ret;
95 }
96