diff options
Diffstat (limited to 'third_party/rust/nix/src/poll.rs')
-rw-r--r-- | third_party/rust/nix/src/poll.rs | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/third_party/rust/nix/src/poll.rs b/third_party/rust/nix/src/poll.rs new file mode 100644 index 0000000000..eb6b241784 --- /dev/null +++ b/third_party/rust/nix/src/poll.rs @@ -0,0 +1,161 @@ +//! Wait for events to trigger on specific file descriptors +#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))] +use sys::time::TimeSpec; +#[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 std::fmt; + +use libc; +use Result; +use errno::Errno; + +/// 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 { + pollfd: libc::pollfd, +} + +impl 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, + events: events.bits(), + revents: EventFlags::empty().bits(), + }, + } + } + + /// Returns the events that occured in the last call to `poll` or `ppoll`. + pub fn revents(&self) -> Option<EventFlags> { + EventFlags::from_bits(self.pollfd.revents) + } +} + +impl fmt::Debug for PollFd { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let pfd = self.pollfd; + let mut ds = f.debug_struct("PollFd"); + ds.field("fd", &pfd.fd); + match EventFlags::from_bits(pfd.events) { + None => ds.field("events", &pfd.events), + Some(ef) => ds.field("events", &ef), + }; + match EventFlags::from_bits(pfd.revents) { + None => ds.field("revents", &pfd.revents), + Some(ef) => ds.field("revents", &ef), + }; + ds.finish() + } +} + +libc_bitflags! { + /// These flags define the different events that can be monitored by `poll` and `ppoll` + pub struct 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://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.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<libc::c_int> { + let res = unsafe { + libc::poll(fds.as_mut_ptr() as *mut libc::pollfd, + fds.len() as libc::nfds_t, + timeout) + }; + + 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)) +/// +/// `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<libc::c_int> { + + + let res = unsafe { + libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd, + fds.len() as libc::nfds_t, + timeout.as_ref(), + sigmask.as_ref()) + }; + Errno::result(res) +} |