| /* Copyright (c) 2016 Google Inc. |
| * Barret Rhoden <brho@cs.berkeley.edu> |
| * See LICENSE for details. |
| * |
| * poll(), implemented on top of our super-spurious select(). |
| * |
| * It's a little backwards to do poll() on select(), but both are pretty lousy |
| * and purely for compatibility on Akaros. For those that use poll, but not |
| * select or epoll, this one's for you. |
| * |
| * All the caveats from our select() apply to poll(). |
| * |
| * Additionally, we won't return POLLNVAL if an FD isn't open. select() will |
| * just fail, and we'll return the error. If anyone has a program that actually |
| * needs that behavior, we can revisit this. |
| * |
| * We won't implicitly track errors like POLLHUP if you also don't ask for at |
| * least POLLIN or POLLOUT. If try to poll for errors only, you'll get nothing. |
| * Likewise, if there is an error/HUP, you'll wake up, but it'll look like a |
| * read/write is ready. (Same with select). You'll notice when you go to |
| * actually read() or write() later, which is pretty much mandatory for this |
| * version of poll(). */ |
| |
| #define _GNU_SOURCE |
| #include <poll.h> |
| #include <sys/select.h> |
| #include <unistd.h> |
| |
| int poll(struct pollfd *fds, nfds_t nfds, int timeout) |
| { |
| struct timespec local_ts, *ts_timeout = 0; |
| |
| if (timeout >= 0) { |
| ts_timeout = &local_ts; |
| ts_timeout->tv_sec = timeout / 1000; |
| ts_timeout->tv_nsec = (timeout % 1000) * 1000000; |
| } |
| return ppoll(fds, nfds, ts_timeout, 0); |
| } |
| |
| int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts, |
| const sigset_t *sigmask) |
| { |
| int max_fd_plus_one = 0; |
| fd_set rd_fds, wr_fds, ex_fds; |
| int ret; |
| |
| FD_ZERO(&rd_fds); |
| FD_ZERO(&wr_fds); |
| FD_ZERO(&ex_fds); |
| for (int i = 0; i < nfds; i++) { |
| if (fds[i].fd == -1) |
| continue; |
| if (max_fd_plus_one < fds[i].fd + 1) |
| max_fd_plus_one = fds[i].fd + 1; |
| if (fds[i].events & (POLLIN | POLLPRI)) |
| FD_SET(i, &rd_fds); |
| if (fds[i].events & POLLOUT) |
| FD_SET(i, &wr_fds); |
| /* TODO: We should be also asking for exceptions on all FDs. |
| * But select is spurious, so it will actually tell us we had |
| * errors on all of our FDs, which will probably confuse |
| * programs. */ |
| } |
| ret = pselect(max_fd_plus_one, &rd_fds, &wr_fds, &ex_fds, timeout_ts, |
| sigmask); |
| if (ret <= 0) |
| return ret; |
| ret = 0; |
| for (int i = 0; i < nfds; i++) { |
| if (fds[i].fd == -1) |
| continue; |
| ret++; |
| fds[i].revents = 0; |
| if (FD_ISSET(i, &rd_fds)) |
| fds[i].revents |= POLLIN | POLLPRI; |
| if (FD_ISSET(i, &wr_fds)) |
| fds[i].revents |= POLLOUT; |
| if (FD_ISSET(i, &ex_fds)) |
| fds[i].revents |= POLLERR | POLLHUP; |
| } |
| return ret; |
| } |