diff --git a/src/poll.rs b/src/poll.rs index 81cb8bd6d1..72e965dbc8 100644 --- a/src/poll.rs +++ b/src/poll.rs @@ -2,10 +2,19 @@ use sys::time::TimeSpec; #[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd", target_os = "dragonfly"))] use sys::signal::SigSet; +use std::os::unix::io::RawFd; use libc; use {Errno, Result}; +/// This is a wrapper around `libc::pollfd`. +/// +/// It's meant to be used as an argument to the [`poll`](fn.poll.html) and +/// [`ppoll`](fn.ppoll.html) functions to specify the events of interested +/// for a specific file descriptor. +/// +/// After a call to `poll` or `ppoll`, the events that occured can be +/// retrieved by calling [`revents()`](#method.revents) on the `PollFd`. #[repr(C)] #[derive(Clone, Copy)] pub struct PollFd { @@ -13,7 +22,9 @@ pub struct PollFd { } impl PollFd { - pub fn new(fd: libc::c_int, events: EventFlags) -> PollFd { + /// Creates a new `PollFd` specifying the events of interested + /// for a given file descriptor. + pub fn new(fd: RawFd, events: EventFlags) -> PollFd { PollFd { pollfd: libc::pollfd { fd: fd, @@ -23,6 +34,7 @@ impl PollFd { } } + /// Returns the events that occured in the last call to `poll` or `ppoll`. pub fn revents(&self) -> Option { EventFlags::from_bits(self.pollfd.revents) } @@ -30,19 +42,73 @@ impl PollFd { libc_bitflags! { pub flags EventFlags: libc::c_short { + /// There is data to read. POLLIN, + /// There is some exceptional condition on the file descriptor. + /// + /// Possibilities include: + /// + /// * There is out-of-band data on a TCP socket (see + /// [tcp(7)](http://man7.org/linux/man-pages/man7/tcp.7.html)). + /// * A pseudoterminal master in packet mode has seen a state + /// change on the slave (see + /// [ioctl_tty(2)](http://man7.org/linux/man-pages/man2/ioctl_tty.2.html)). + /// * A cgroup.events file has been modified (see + /// [cgroups(7)](http://man7.org/linux/man-pages/man7/cgroups.7.html)). POLLPRI, + /// Writing is now possible, though a write larger that the + /// available space in a socket or pipe will still block (unless + /// `O_NONBLOCK` is set). POLLOUT, + /// Equivalent to [`POLLIN`](constant.POLLIN.html) POLLRDNORM, + /// Equivalent to [`POLLOUT`](constant.POLLOUT.html) POLLWRNORM, + /// Priority band data can be read (generally unused on Linux). POLLRDBAND, + /// Priority data may be written. POLLWRBAND, + /// Error condition (only returned in + /// [`PollFd::revents`](struct.PollFd.html#method.revents); + /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)). + /// This bit is also set for a file descriptor referring to the + /// write end of a pipe when the read end has been closed. POLLERR, + /// Hang up (only returned in [`PollFd::revents`](struct.PollFd.html#method.revents); + /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)). + /// Note that when reading from a channel such as a pipe or a stream + /// socket, this event merely indicates that the peer closed its + /// end of the channel. Subsequent reads from the channel will + /// return 0 (end of file) only after all outstanding data in the + /// channel has been consumed. POLLHUP, + /// Invalid request: `fd` not open (only returned in + /// [`PollFd::revents`](struct.PollFd.html#method.revents); + /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)). POLLNVAL, } } +/// `poll` waits for one of a set of file descriptors to become ready to perform I/O. +/// ([`poll(2)`](http://man7.org/linux/man-pages/man2/poll.2.html)) +/// +/// `fds` is a slice containing all [`PollFd`](struct.PollFd.html) to poll. +/// The function will return as soon as one event registered in one of the `PollFd` occurs. +/// +/// The `timeout` argument specifies the number of milliseconds that `poll()` +/// should block waiting for a file descriptor to become ready. The call +/// will block until either: +/// +/// * a file descriptor becomes ready; +/// * the call is interrupted by a signal handler; or +/// * the timeout expires. +/// +/// Note that the timeout interval will be rounded up to the system clock +/// granularity, and kernel scheduling delays mean that the blocking +/// interval may overrun by a small amount. Specifying a negative value +/// in timeout means an infinite timeout. Specifying a timeout of zero +/// causes `poll()` to return immediately, even if no file descriptors are +/// ready. pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result { let res = unsafe { libc::poll(fds.as_mut_ptr() as *mut libc::pollfd, @@ -53,6 +119,31 @@ pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result { Errno::result(res) } +/// `ppoll()` allows an application to safely wait until either a file +/// descriptor becomes ready or until a signal is caught. +/// ([`poll(2)`](http://man7.org/linux/man-pages/man2/poll.2.html)) +/// +/// The operation of `ppoll` is identical to `poll`, other than these two differences: +/// +/// * `timeout` is a `TimeSpec` which can specify time with nanosecond precision. +/// * `ppoll` changes the signal set whose delivery are blocked for the caller before polling +/// the file descriptors. This set is reverted after the polling. +/// Note that this is done **atomically**. +/// +/// It is equivalent to *atomically* executing the following calls +/// (expressed here in C): +/// +/// ```c +/// sigset_t origmask; +/// int timeout; +/// +/// timeout = (tmo_p == NULL) ? -1 : +/// (tmo_p->tv_sec * 1000 + tmo_p->tv_nsec / 1000000); +/// pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); +/// ready = poll(&fds, nfds, timeout); +/// pthread_sigmask(SIG_SETMASK, &origmask, NULL); +/// ``` +/// #[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd", target_os = "dragonfly"))] pub fn ppoll(fds: &mut [PollFd], timeout: TimeSpec, sigmask: SigSet) -> Result {