vmm: refactor userspace's emsr_fakewrite()
[akaros.git] / user / iplib / poll.c
1 /* Copyright (c) 2016 Google Inc.
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * poll(), implemented on top of our super-spurious select().
6  *
7  * It's a little backwards to do poll() on select(), but both are pretty lousy
8  * and purely for compatibility on Akaros.  For those that use poll, but not
9  * select or epoll, this one's for you.
10  *
11  * All the caveats from our select() apply to poll().
12  *
13  * Additionally, we won't return POLLNVAL if an FD isn't open.  select() will
14  * just fail, and we'll return the error.  If anyone has a program that actually
15  * needs that behavior, we can revisit this.
16  *
17  * We won't implicitly track errors like POLLHUP if you also don't ask for at
18  * least POLLIN or POLLOUT.  If try to poll for errors only, you'll get nothing.
19  * Likewise, if there is an error/HUP, you'll wake up, but it'll look like a
20  * read/write is ready.  (Same with select).  You'll notice when you go to
21  * actually read() or write() later, which is pretty much mandatory for this
22  * version of poll(). */
23
24 #define _GNU_SOURCE
25 #include <poll.h>
26 #include <sys/select.h>
27 #include <unistd.h>
28
29 int poll(struct pollfd *fds, nfds_t nfds, int timeout)
30 {
31         struct timespec local_ts, *ts_timeout = 0;
32
33         if (timeout >= 0) {
34                 ts_timeout = &local_ts;
35                 ts_timeout->tv_sec = timeout / 1000;
36                 ts_timeout->tv_nsec = (timeout % 1000) * 1000000;
37         }
38         return ppoll(fds, nfds, ts_timeout, 0);
39 }
40
41 int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts,
42           const sigset_t *sigmask)
43 {
44         int max_fd_plus_one = 0;
45         fd_set rd_fds, wr_fds, ex_fds;
46         int ret;
47
48         FD_ZERO(&rd_fds);
49         FD_ZERO(&wr_fds);
50         FD_ZERO(&ex_fds);
51         for (int i = 0; i < nfds; i++) {
52                 if (fds[i].fd == -1)
53                         continue;
54                 if (max_fd_plus_one < fds[i].fd + 1)
55                         max_fd_plus_one = fds[i].fd + 1;
56                 if (fds[i].events & (POLLIN | POLLPRI))
57                         FD_SET(i, &rd_fds);
58                 if (fds[i].events & POLLOUT)
59                         FD_SET(i, &wr_fds);
60                 /* TODO: We should be also asking for exceptions on all FDs.
61                  * But select is spurious, so it will actually tell us we had
62                  * errors on all of our FDs, which will probably confuse
63                  * programs. */
64         }
65         ret = pselect(max_fd_plus_one, &rd_fds, &wr_fds, &ex_fds, timeout_ts,
66                       sigmask);
67         if (ret <= 0)
68                 return ret;
69         ret = 0;
70         for (int i = 0; i < nfds; i++) {
71                 if (fds[i].fd == -1)
72                         continue;
73                 ret++;
74                 fds[i].revents = 0;
75                 if (FD_ISSET(i, &rd_fds))
76                         fds[i].revents |= POLLIN | POLLPRI;
77                 if (FD_ISSET(i, &wr_fds))
78                         fds[i].revents |= POLLOUT;
79                 if (FD_ISSET(i, &ex_fds))
80                         fds[i].revents |= POLLERR | POLLHUP;
81         }
82         return ret;
83 }