Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add poll module in Android #672

Merged
merged 2 commits into from
Jul 30, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,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
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ pub mod mqueue;

pub mod pty;

#[cfg(any(target_os = "linux", target_os = "macos"))]
pub mod poll;

pub mod net;
Expand Down
82 changes: 78 additions & 4 deletions src/poll.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
#[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 {
pollfd: libc::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,
Expand All @@ -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> {
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<libc::c_int> {
let res = unsafe {
libc::poll(fds.as_mut_ptr() as *mut libc::pollfd,
Expand All @@ -53,7 +120,14 @@ pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> {
Errno::result(res)
}

#[cfg(any(target_os = "linux", target_os = "android"))]
/// `ppoll()` allows an application to safely wait until either a file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's try to shorten this a bit so it looks better in the docs. The man page starts with "wait for some event on a file descriptor". I think that's descriptive and succinct and I suggest you use that here instead.

Copy link
Contributor Author

@ndusart ndusart Jul 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I wanted to focus on the difference between poll and ppoll. Should I just put the first line of man, and redirect to the web page for more info ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Distinguishing them would be good, I just wanted the description to be a little shorter so I grabbed it from the man page. Maybe instead say "Like poll() but can also wait for signals". How's that sound?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

poll returns also on signals but the caller do not control what. But I agree that something like "Like poll() but let you precise what signals may interrupt it" is enough. I'll change that.

/// 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> {


Expand Down
1 change: 0 additions & 1 deletion test/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))]
Expand Down