blob: 7b86d475f2d29a422cf6226bb581eac2fd590728 [file] [log] [blame]
/* 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;
}