diff --git a/CHANGELOG.md b/CHANGELOG.md index d5064c9c8c..688b0dcca5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). - On Linux and Android, added support for receiving `PTRACE_O_TRACESYSGOOD` events from `wait` and `waitpid` using `WaitStatus::PtraceSyscall` ([#566](https://github.com/nix-rust/nix/pull/566)). +- Added `nix::poll` module for all platforms + ([#672](https://github.com/nix-rust/nix/pull/672)) +- Added `nix::ppoll` function for FreeBSD and DragonFly + ([#672](https://github.com/nix-rust/nix/pull/672)) ### Changed - The `ioctl!` macro and its variants now allow the generated functions to have diff --git a/src/lib.rs b/src/lib.rs index 3518efacf7..cadc7fb41f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,7 +39,6 @@ pub mod mqueue; pub mod pty; -#[cfg(any(target_os = "linux", target_os = "macos"))] pub mod poll; pub mod net; diff --git a/src/poll.rs b/src/poll.rs index afc5bd9c95..60c31aceed 100644 --- a/src/poll.rs +++ b/src/poll.rs @@ -1,11 +1,20 @@ -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] use sys::time::TimeSpec; -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] 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 interest +/// 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 interest + /// for a given file descriptor. + pub fn new(fd: RawFd, events: EventFlags) -> PollFd { PollFd { pollfd: libc::pollfd { fd: fd, @@ -23,26 +34,82 @@ 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) } } libc_bitflags! { + /// These flags define the different events that can be monitored by `poll` and `ppoll` 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` contains all [`PollFd`](struct.PollFd.html) to poll. +/// The function will return as soon as any event occur for any of these `PollFd`s. +/// +/// 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,7 +120,14 @@ pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result { Errno::result(res) } -#[cfg(any(target_os = "linux", target_os = "android"))] +/// `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)) +/// +/// `ppoll` behaves like `poll`, but let you specify what signals may interrupt it +/// with the `sigmask` argument. +/// +#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] pub fn ppoll(fds: &mut [PollFd], timeout: TimeSpec, sigmask: SigSet) -> Result { diff --git a/test/test.rs b/test/test.rs index fab499ce49..1d22b59af8 100644 --- a/test/test.rs +++ b/test/test.rs @@ -15,7 +15,6 @@ mod test_fcntl; mod test_mq; mod test_net; mod test_nix_path; -#[cfg(any(target_os = "linux", target_os = "macos"))] mod test_poll; mod test_pty; #[cfg(any(target_os = "linux", target_os = "android"))]