summaryrefslogtreecommitdiff
path: root/src/sys
diff options
context:
space:
mode:
Diffstat (limited to 'src/sys')
-rw-r--r--src/sys/aio.rs643
1 files changed, 552 insertions, 91 deletions
diff --git a/src/sys/aio.rs b/src/sys/aio.rs
index 687458e5..d5561e9c 100644
--- a/src/sys/aio.rs
+++ b/src/sys/aio.rs
@@ -1,3 +1,25 @@
+//! POSIX Asynchronous I/O
+//!
+//! The POSIX AIO interface is used for asynchronous I/O on files and disk-like
+//! devices. It supports [`read`](struct.AioCb.html#method.read),
+//! [`write`](struct.AioCb.html#method.write), and
+//! [`fsync`](struct.AioCb.html#method.fsync) operations. Completion
+//! notifications can optionally be delivered via
+//! [signals](../signal/enum.SigevNotify.html#variant.SigevSignal), via the
+//! [`aio_suspend`](fn.aio_suspend.html) function, or via polling. Some
+//! platforms support other completion
+//! notifications, such as
+//! [kevent](../signal/enum.SigevNotify.html#variant.SigevKevent).
+//!
+//! Multiple operations may be submitted in a batch with
+//! [`lio_listio`](fn.lio_listio.html), though the standard does not guarantee
+//! that they will be executed atomically.
+//!
+//! Outstanding operations may be cancelled with
+//! [`cancel`](struct.AioCb.html#method.cancel) or
+//! [`aio_cancel_all`](fn.aio_cancel_all.html), though the operating system may
+//! not support this for all filesystems and devices.
+
use {Error, Result};
use bytes::{Bytes, BytesMut};
use errno::Errno;
@@ -13,9 +35,9 @@ use std::ptr::{null, null_mut};
use sys::signal::*;
use sys::time::TimeSpec;
-/// Mode for `AioCb::fsync`. Controls whether only data or both data and
-/// metadata are synced.
libc_enum! {
+ /// Mode for `AioCb::fsync`. Controls whether only data or both data and
+ /// metadata are synced.
#[repr(i32)]
pub enum AioFsyncMode {
/// do it like `fsync`
@@ -31,9 +53,9 @@ libc_enum! {
}
libc_enum! {
- /// When used with `lio_listio`, determines whether a given `aiocb` should be
- /// used for a read operation, a write operation, or ignored. Has no effect for
- /// any other aio functions.
+ /// When used with [`lio_listio`](fn.lio_listio.html), determines whether a
+ /// given `aiocb` should be used for a read operation, a write operation, or
+ /// ignored. Has no effect for any other aio functions.
#[repr(i32)]
pub enum LioOpcode {
LIO_NOP,
@@ -43,18 +65,19 @@ libc_enum! {
}
libc_enum! {
- /// Mode for `lio_listio`.
+ /// Mode for [`lio_listio`](fn.lio_listio.html)
#[repr(i32)]
pub enum LioMode {
- /// Requests that `lio_listio` block until all requested operations have
- /// been completed
+ /// Requests that [`lio_listio`](fn.lio_listio.html) block until all
+ /// requested operations have been completed
LIO_WAIT,
- /// Requests that `lio_listio` return immediately
+ /// Requests that [`lio_listio`](fn.lio_listio.html) return immediately
LIO_NOWAIT,
}
}
-/// Return values for `AioCb::cancel and aio_cancel_all`
+/// Return values for [`AioCb::cancel`](struct.AioCb.html#method.cancel) and
+/// [`aio_cancel_all`](fn.aio_cancel_all.html)
#[repr(i32)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum AioCancelStat {
@@ -113,15 +136,20 @@ impl<'a> Buffer<'a> {
}
}
-/// The basic structure used by all aio functions. Each `aiocb` represents one
+/// AIO Control Block.
+///
+/// The basic structure used by all aio functions. Each `AioCb` represents one
/// I/O request.
pub struct AioCb<'a> {
aiocb: libc::aiocb,
- /// Tracks whether the buffer pointed to by aiocb.aio_buf is mutable
+ /// Tracks whether the buffer pointed to by `libc::aiocb.aio_buf` is mutable
mutable: bool,
/// Could this `AioCb` potentially have any in-kernel state?
in_progress: bool,
- /// Used to keep buffers from Drop'ing
+ /// Optionally keeps a reference to the data.
+ ///
+ /// Used to keep buffers from `Drop`'ing, and may be returned once the
+ /// `AioCb` is completed by `into_buffer`.
buffer: Buffer<'a>
}
@@ -146,11 +174,40 @@ impl<'a> AioCb<'a> {
///
/// The resulting `AioCb` structure is suitable for use with `AioCb::fsync`.
///
- /// * `fd` File descriptor. Required for all aio functions.
- /// * `prio` If POSIX Prioritized IO is supported, then the operation will
- /// be prioritized at the process's priority level minus `prio`
- /// * `sigev_notify` Determines how you will be notified of event
- /// completion.
+ /// # Parameters
+ ///
+ /// * `fd`: File descriptor. Required for all aio functions.
+ /// * `prio`: If POSIX Prioritized IO is supported, then the
+ /// operation will be prioritized at the process's
+ /// priority level minus `prio`.
+ /// * `sigev_notify`: Determines how you will be notified of event
+ /// completion.
+ ///
+ /// # Examples
+ ///
+ /// Create an `AioCb` from a raw file descriptor and use it for an
+ /// [`fsync`](#method.from_bytes_mut) operation.
+ ///
+ /// ```
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify::SigevNone;
+ /// # use std::{thread, time};
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// let f = tempfile().unwrap();
+ /// let mut aiocb = AioCb::from_fd( f.as_raw_fd(), 0, SigevNone);
+ /// aiocb.fsync(AioFsyncMode::O_SYNC).expect("aio_fsync failed early");
+ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
+ /// thread::sleep(time::Duration::from_millis(10));
+ /// }
+ /// aiocb.aio_return().expect("aio_fsync failed late");
+ /// # }
+ /// ```
pub fn from_fd(fd: RawFd, prio: libc::c_int,
sigev_notify: SigevNotify) -> AioCb<'a> {
let mut a = AioCb::common_init(fd, prio, sigev_notify);
@@ -166,17 +223,65 @@ impl<'a> AioCb<'a> {
}
}
- /// Constructs a new `AioCb`.
+ /// Constructs a new `AioCb` from a mutable slice.
+ ///
+ /// The resulting `AioCb` will be suitable for both read and write
+ /// operations, but only if the borrow checker can guarantee that the slice
+ /// will outlive the `AioCb`. That will usually be the case if the `AioCb`
+ /// is stack-allocated. If the borrow checker gives you trouble, try using
+ /// [`from_bytes_mut`](#method.from_bytes_mut) instead.
///
- /// * `fd` File descriptor. Required for all aio functions.
- /// * `offs` File offset
- /// * `buf` A memory buffer
- /// * `prio` If POSIX Prioritized IO is supported, then the operation will
- /// be prioritized at the process's priority level minus `prio`
- /// * `sigev_notify` Determines how you will be notified of event
- /// completion.
- /// * `opcode` This field is only used for `lio_listio`. It determines
- /// which operation to use for this individual aiocb
+ /// # Parameters
+ ///
+ /// * `fd`: File descriptor. Required for all aio functions.
+ /// * `offs`: File offset
+ /// * `buf`: A memory buffer
+ /// * `prio`: If POSIX Prioritized IO is supported, then the
+ /// operation will be prioritized at the process's
+ /// priority level minus `prio`
+ /// * `sigev_notify`: Determines how you will be notified of event
+ /// completion.
+ /// * `opcode`: This field is only used for `lio_listio`. It
+ /// determines which operation to use for this individual
+ /// aiocb
+ ///
+ /// # Examples
+ ///
+ /// Create an `AioCb` from a mutable slice and read into it.
+ ///
+ /// ```
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::{thread, time};
+ /// # use std::io::Write;
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// const INITIAL: &[u8] = b"abcdef123456";
+ /// const LEN: usize = 4;
+ /// let mut rbuf = vec![0; LEN];
+ /// let mut f = tempfile().unwrap();
+ /// f.write_all(INITIAL).unwrap();
+ /// {
+ /// let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(),
+ /// 2, //offset
+ /// &mut rbuf,
+ /// 0, //priority
+ /// SigevNotify::SigevNone,
+ /// LioOpcode::LIO_NOP);
+ /// aiocb.read().unwrap();
+ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
+ /// thread::sleep(time::Duration::from_millis(10));
+ /// }
+ /// assert_eq!(aiocb.aio_return().unwrap() as usize, LEN);
+ /// }
+ /// assert_eq!(rbuf, b"cdef");
+ /// # }
+ /// ```
pub fn from_mut_slice(fd: RawFd, offs: off_t, buf: &'a mut [u8],
prio: libc::c_int, sigev_notify: SigevNotify,
opcode: LioOpcode) -> AioCb<'a> {
@@ -194,24 +299,62 @@ impl<'a> AioCb<'a> {
}
}
- /// Constructs a new `AioCb`.
+ /// Constructs a new `AioCb` from a `Bytes` object.
///
- /// Unlike `from_mut_slice`, this method returns a structure suitable for
+ /// Unlike `from_slice`, this method returns a structure suitable for
/// placement on the heap. It may be used for write operations, but not
/// read operations.
///
- /// * `fd` File descriptor. Required for all aio functions.
- /// * `offs` File offset
- /// * `buf` A shared memory buffer
- /// * `prio` If POSIX Prioritized IO is supported, then the operation will
- /// be prioritized at the process's priority level minus `prio`
- /// * `sigev_notify` Determines how you will be notified of event
- /// completion.
- /// * `opcode` This field is only used for `lio_listio`. It determines
- /// which operation to use for this individual aiocb
+ /// # Parameters
+ ///
+ /// * `fd`: File descriptor. Required for all aio functions.
+ /// * `offs`: File offset
+ /// * `buf`: A shared memory buffer
+ /// * `prio`: If POSIX Prioritized IO is supported, then the
+ /// operation will be prioritized at the process's
+ /// priority level minus `prio`
+ /// * `sigev_notify`: Determines how you will be notified of event
+ /// completion.
+ /// * `opcode`: This field is only used for `lio_listio`. It
+ /// determines which operation to use for this individual
+ /// aiocb
+ ///
+ /// # Examples
+ ///
+ /// Create an `AioCb` from a `Bytes` object and use it for writing.
+ ///
+ /// ```
+ /// # extern crate bytes;
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use bytes::Bytes;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::{thread, time};
+ /// # use std::io::Write;
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// let wbuf = Bytes::from(&b"CDEF"[..]);
+ /// let mut f = tempfile().unwrap();
+ /// let mut aiocb = AioCb::from_bytes( f.as_raw_fd(),
+ /// 2, //offset
+ /// wbuf.clone(),
+ /// 0, //priority
+ /// SigevNotify::SigevNone,
+ /// LioOpcode::LIO_NOP);
+ /// aiocb.write().unwrap();
+ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
+ /// thread::sleep(time::Duration::from_millis(10));
+ /// }
+ /// assert_eq!(aiocb.aio_return().unwrap() as usize, wbuf.len());
+ /// # }
+ /// ```
pub fn from_bytes(fd: RawFd, offs: off_t, buf: Bytes,
prio: libc::c_int, sigev_notify: SigevNotify,
- opcode: LioOpcode) -> AioCb<'a> {
+ opcode: LioOpcode) -> AioCb<'a> {
// Small BytesMuts are stored inline. Inline storage is a no-no,
// because we store a pointer to the buffer in the AioCb before
// returning the Buffer by move. If the buffer is too small, reallocate
@@ -240,20 +383,66 @@ impl<'a> AioCb<'a> {
}
}
- /// Constructs a new `AioCb`.
+ /// Constructs a new `AioCb` from a `BytesMut` object.
///
/// Unlike `from_mut_slice`, this method returns a structure suitable for
/// placement on the heap. It may be used for both reads and writes.
///
- /// * `fd` File descriptor. Required for all aio functions.
- /// * `offs` File offset
- /// * `buf` A shared memory buffer
- /// * `prio` If POSIX Prioritized IO is supported, then the operation will
- /// be prioritized at the process's priority level minus `prio`
- /// * `sigev_notify` Determines how you will be notified of event
- /// completion.
- /// * `opcode` This field is only used for `lio_listio`. It determines
- /// which operation to use for this individual aiocb
+ /// # Parameters
+ ///
+ /// * `fd`: File descriptor. Required for all aio functions.
+ /// * `offs`: File offset
+ /// * `buf`: An owned memory buffer
+ /// * `prio`: If POSIX Prioritized IO is supported, then the
+ /// operation will be prioritized at the process's
+ /// priority level minus `prio`
+ /// * `sigev_notify`: Determines how you will be notified of event
+ /// completion.
+ /// * `opcode`: This field is only used for `lio_listio`. It
+ /// determines which operation to use for this individual
+ /// aiocb
+ ///
+ /// # Examples
+ ///
+ /// Create an `AioCb` from a `BytesMut` and use it for reading. In this
+ /// example the `AioCb` is stack-allocated, so we could've used
+ /// `from_mut_slice` instead.
+ ///
+ /// ```
+ /// # extern crate bytes;
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use bytes::BytesMut;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::{thread, time};
+ /// # use std::io::Write;
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// const INITIAL: &[u8] = b"abcdef123456";
+ /// const LEN: usize = 4;
+ /// let rbuf = BytesMut::from(vec![0; LEN]);
+ /// let mut f = tempfile().unwrap();
+ /// f.write_all(INITIAL).unwrap();
+ /// let mut aiocb = AioCb::from_bytes_mut( f.as_raw_fd(),
+ /// 2, //offset
+ /// rbuf,
+ /// 0, //priority
+ /// SigevNotify::SigevNone,
+ /// LioOpcode::LIO_NOP);
+ /// aiocb.read().unwrap();
+ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
+ /// thread::sleep(time::Duration::from_millis(10));
+ /// }
+ /// assert_eq!(aiocb.aio_return().unwrap() as usize, LEN);
+ /// let buffer = aiocb.into_buffer();
+ /// const EXPECT: &[u8] = b"cdef";
+ /// assert_eq!(buffer.bytes_mut().unwrap(), EXPECT);
+ /// # }
+ /// ```
pub fn from_bytes_mut(fd: RawFd, offs: off_t, buf: BytesMut,
prio: libc::c_int, sigev_notify: SigevNotify,
opcode: LioOpcode) -> AioCb<'a> {
@@ -281,22 +470,31 @@ impl<'a> AioCb<'a> {
/// Constructs a new `AioCb` from a mutable raw pointer
///
- /// * `fd` File descriptor. Required for all aio functions.
- /// * `offs` File offset
- /// * `buf` Pointer to the memory buffer
- /// * `len` Length of the buffer pointed to by `buf`
- /// * `prio` If POSIX Prioritized IO is supported, then the operation will
- /// be prioritized at the process's priority level minus `prio`
- /// * `sigev_notify` Determines how you will be notified of event
- /// completion.
- /// * `opcode` This field is only used for `lio_listio`. It determines
- /// which operation to use for this individual aiocb
+ /// Unlike `from_mut_slice`, this method returns a structure suitable for
+ /// placement on the heap. It may be used for both reads and writes. Due
+ /// to its unsafety, this method is not recommended. It is most useful when
+ /// heap allocation is required but for some reason the data cannot be
+ /// converted to a `BytesMut`.
+ ///
+ /// # Parameters
+ ///
+ /// * `fd`: File descriptor. Required for all aio functions.
+ /// * `offs`: File offset
+ /// * `buf`: Pointer to the memory buffer
+ /// * `len`: Length of the buffer pointed to by `buf`
+ /// * `prio`: If POSIX Prioritized IO is supported, then the
+ /// operation will be prioritized at the process's
+ /// priority level minus `prio`
+ /// * `sigev_notify`: Determines how you will be notified of event
+ /// completion.
+ /// * `opcode`: This field is only used for `lio_listio`. It
+ /// determines which operation to use for this individual
+ /// aiocb
///
/// # Safety
///
- /// Unsafe because using this `AioCb` will cause `libc::aio_read` or
- /// `libc::aio_write` to dereference a raw pointer, without type, bounds, or
- /// lifetime checking.
+ /// The caller must ensure that the storage pointed to by `buf` outlives the
+ /// `AioCb`. The lifetime checker can't help here.
pub unsafe fn from_mut_ptr(fd: RawFd, offs: off_t,
buf: *mut c_void, len: usize,
prio: libc::c_int, sigev_notify: SigevNotify,
@@ -315,23 +513,32 @@ impl<'a> AioCb<'a> {
}
}
- /// Constructs a new `AioCb` from a raw pointer
+ /// Constructs a new `AioCb` from a raw pointer.
+ ///
+ /// Unlike `from_slice`, this method returns a structure suitable for
+ /// placement on the heap. Due to its unsafety, this method is not
+ /// recommended. It is most useful when heap allocation is required but for
+ /// some reason the data cannot be converted to a `Bytes`.
///
- /// * `fd` File descriptor. Required for all aio functions.
- /// * `offs` File offset
- /// * `buf` Pointer to the memory buffer
- /// * `len` Length of the buffer pointed to by `buf`
- /// * `prio` If POSIX Prioritized IO is supported, then the operation will
- /// be prioritized at the process's priority level minus `prio`
- /// * `sigev_notify` Determines how you will be notified of event
- /// completion.
- /// * `opcode` This field is only used for `lio_listio`. It determines
- /// which operation to use for this individual aiocb
+ /// # Parameters
+ ///
+ /// * `fd`: File descriptor. Required for all aio functions.
+ /// * `offs`: File offset
+ /// * `buf`: Pointer to the memory buffer
+ /// * `len`: Length of the buffer pointed to by `buf`
+ /// * `prio`: If POSIX Prioritized IO is supported, then the
+ /// operation will be prioritized at the process's
+ /// priority level minus `prio`
+ /// * `sigev_notify`: Determines how you will be notified of event
+ /// completion.
+ /// * `opcode`: This field is only used for `lio_listio`. It
+ /// determines which operation to use for this individual
+ /// aiocb
///
/// # Safety
///
- /// Unsafe because using this `AioCb` will cause `libc::aio_write` to
- /// dereference a raw pointer, without type, bounds, or lifetime checking.
+ /// The caller must ensure that the storage pointed to by `buf` outlives the
+ /// `AioCb`. The lifetime checker can't help here.
pub unsafe fn from_ptr(fd: RawFd, offs: off_t,
buf: *const c_void, len: usize,
prio: libc::c_int, sigev_notify: SigevNotify,
@@ -357,14 +564,44 @@ impl<'a> AioCb<'a> {
///
/// An `AioCb` created this way cannot be used with `read`, and its
/// `LioOpcode` cannot be set to `LIO_READ`. This method is useful when
- /// writing a const buffer with `AioCb::write`, since from_mut_slice can't
+ /// writing a const buffer with `AioCb::write`, since `from_mut_slice` can't
/// work with const buffers.
+ ///
+ /// # Examples
+ ///
+ /// Construct an `AioCb` from a slice and use it for writing.
+ ///
+ /// ```
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::{thread, time};
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// const WBUF: &[u8] = b"abcdef123456";
+ /// let mut f = tempfile().unwrap();
+ /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
+ /// 2, //offset
+ /// WBUF,
+ /// 0, //priority
+ /// SigevNotify::SigevNone,
+ /// LioOpcode::LIO_NOP);
+ /// aiocb.write().unwrap();
+ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
+ /// thread::sleep(time::Duration::from_millis(10));
+ /// }
+ /// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
+ /// # }
+ /// ```
// Note: another solution to the problem of writing const buffers would be
// to genericize AioCb for both &mut [u8] and &[u8] buffers. AioCb::read
// could take the former and AioCb::write could take the latter. However,
// then lio_listio wouldn't work, because that function needs a slice of
- // AioCb, and they must all be the same type. We're basically stuck with
- // using an unsafe function, since aio (as designed in C) is an unsafe API.
+ // AioCb, and they must all be of the same type.
pub fn from_slice(fd: RawFd, offs: off_t, buf: &'a [u8],
prio: libc::c_int, sigev_notify: SigevNotify,
opcode: LioOpcode) -> AioCb {
@@ -418,6 +655,56 @@ impl<'a> AioCb<'a> {
}
/// Cancels an outstanding AIO request.
+ ///
+ /// The operating system is not required to implement cancellation for all
+ /// file and device types. Even if it does, there is no guarantee that the
+ /// operation has not already completed. So the caller must check the
+ /// result and handle operations that were not canceled or that have already
+ /// completed.
+ ///
+ /// # Examples
+ ///
+ /// Cancel an outstanding aio operation. Note that we must still call
+ /// `aio_return` to free resources, even though we don't care about the
+ /// result.
+ ///
+ /// ```
+ /// # extern crate bytes;
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use bytes::Bytes;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::{thread, time};
+ /// # use std::io::Write;
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// let wbuf = Bytes::from(&b"CDEF"[..]);
+ /// let mut f = tempfile().unwrap();
+ /// let mut aiocb = AioCb::from_bytes( f.as_raw_fd(),
+ /// 2, //offset
+ /// wbuf.clone(),
+ /// 0, //priority
+ /// SigevNotify::SigevNone,
+ /// LioOpcode::LIO_NOP);
+ /// aiocb.write().unwrap();
+ /// let cs = aiocb.cancel().unwrap();
+ /// if cs == AioCancelStat::AioNotCanceled {
+ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
+ /// thread::sleep(time::Duration::from_millis(10));
+ /// }
+ /// }
+ /// // Must call `aio_return`, but ignore the result
+ /// let _ = aiocb.aio_return();
+ /// # }
+ /// ```
+ ///
+ /// # References
+ ///
+ /// [aio_cancel](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html)
pub fn cancel(&mut self) -> Result<AioCancelStat> {
match unsafe { libc::aio_cancel(self.aiocb.aio_fildes, &mut self.aiocb) } {
libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled),
@@ -428,9 +715,46 @@ impl<'a> AioCb<'a> {
}
}
- /// Retrieve error status of an asynchronous operation. If the request has
- /// not yet completed, returns `EINPROGRESS`. Otherwise, returns `Ok` or
- /// any other error.
+ /// Retrieve error status of an asynchronous operation.
+ ///
+ /// If the request has not yet completed, returns `EINPROGRESS`. Otherwise,
+ /// returns `Ok` or any other error.
+ ///
+ /// # Examples
+ ///
+ /// Issue an aio operation and use `error` to poll for completion. Polling
+ /// is an alternative to `aio_suspend`, used by most of the other examples.
+ ///
+ /// ```
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::{thread, time};
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// const WBUF: &[u8] = b"abcdef123456";
+ /// let mut f = tempfile().unwrap();
+ /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
+ /// 2, //offset
+ /// WBUF,
+ /// 0, //priority
+ /// SigevNotify::SigevNone,
+ /// LioOpcode::LIO_NOP);
+ /// aiocb.write().unwrap();
+ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
+ /// thread::sleep(time::Duration::from_millis(10));
+ /// }
+ /// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
+ /// # }
+ /// ```
+ ///
+ /// # References
+ ///
+ /// [aio_error](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_error.html)
pub fn error(&mut self) -> Result<()> {
match unsafe { libc::aio_error(&mut self.aiocb as *mut libc::aiocb) } {
0 => Ok(()),
@@ -440,7 +764,11 @@ impl<'a> AioCb<'a> {
}
}
- /// An asynchronous version of `fsync`.
+ /// An asynchronous version of `fsync(2)`.
+ ///
+ /// # References
+ ///
+ /// [aio_fsync](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_fsync.html)
pub fn fsync(&mut self, mode: AioFsyncMode) -> Result<()> {
let p: *mut libc::aiocb = &mut self.aiocb;
Errno::result(unsafe {
@@ -483,6 +811,10 @@ impl<'a> AioCb<'a> {
}
/// Asynchronously reads from a file descriptor into a buffer
+ ///
+ /// # References
+ ///
+ /// [aio_read](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_read.html)
pub fn read(&mut self) -> Result<()> {
assert!(self.mutable, "Can't read into an immutable buffer");
let p: *mut libc::aiocb = &mut self.aiocb;
@@ -498,9 +830,15 @@ impl<'a> AioCb<'a> {
SigEvent::from(&self.aiocb.aio_sigevent)
}
- /// Retrieve return status of an asynchronous operation. Should only be
- /// called once for each `AioCb`, after `AioCb::error` indicates that it has
- /// completed. The result is the same as for `read`, `write`, of `fsync`.
+ /// Retrieve return status of an asynchronous operation.
+ ///
+ /// Should only be called once for each `AioCb`, after `AioCb::error`
+ /// indicates that it has completed. The result is the same as for the
+ /// synchronous `read(2)`, `write(2)`, of `fsync(2)` functions.
+ ///
+ /// # References
+ ///
+ /// [aio_return](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_return.html)
// Note: this should be just `return`, but that's a reserved word
pub fn aio_return(&mut self) -> Result<isize> {
let p: *mut libc::aiocb = &mut self.aiocb;
@@ -509,6 +847,10 @@ impl<'a> AioCb<'a> {
}
/// Asynchronously writes from a buffer to a file descriptor
+ ///
+ /// # References
+ ///
+ /// [aio_write](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_write.html)
pub fn write(&mut self) -> Result<()> {
let p: *mut libc::aiocb = &mut self.aiocb;
Errno::result(unsafe {
@@ -520,7 +862,50 @@ impl<'a> AioCb<'a> {
}
-/// Cancels outstanding AIO requests. All requests for `fd` will be cancelled.
+/// Cancels outstanding AIO requests for a given file descriptor.
+///
+/// # Examples
+///
+/// Issue an aio operation, then cancel all outstanding operations on that file
+/// descriptor.
+///
+/// ```
+/// # extern crate bytes;
+/// # extern crate tempfile;
+/// # extern crate nix;
+/// # use nix::errno::Errno;
+/// # use nix::Error;
+/// # use bytes::Bytes;
+/// # use nix::sys::aio::*;
+/// # use nix::sys::signal::SigevNotify;
+/// # use std::{thread, time};
+/// # use std::io::Write;
+/// # use std::os::unix::io::AsRawFd;
+/// # use tempfile::tempfile;
+/// # fn main() {
+/// let wbuf = Bytes::from(&b"CDEF"[..]);
+/// let mut f = tempfile().unwrap();
+/// let mut aiocb = AioCb::from_bytes( f.as_raw_fd(),
+/// 2, //offset
+/// wbuf.clone(),
+/// 0, //priority
+/// SigevNotify::SigevNone,
+/// LioOpcode::LIO_NOP);
+/// aiocb.write().unwrap();
+/// let cs = aio_cancel_all(f.as_raw_fd()).unwrap();
+/// if cs == AioCancelStat::AioNotCanceled {
+/// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
+/// thread::sleep(time::Duration::from_millis(10));
+/// }
+/// }
+/// // Must call `aio_return`, but ignore the result
+/// let _ = aiocb.aio_return();
+/// # }
+/// ```
+///
+/// # References
+///
+/// [`aio_cancel`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html)
pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> {
match unsafe { libc::aio_cancel(fd, null_mut()) } {
libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled),
@@ -532,8 +917,42 @@ pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> {
}
/// Suspends the calling process until at least one of the specified `AioCb`s
-/// has completed, a signal is delivered, or the timeout has passed. If
-/// `timeout` is `None`, `aio_suspend` will block indefinitely.
+/// has completed, a signal is delivered, or the timeout has passed.
+///
+/// If `timeout` is `None`, `aio_suspend` will block indefinitely.
+///
+/// # Examples
+///
+/// Use `aio_suspend` to block until an aio operation completes.
+///
+// Disable doctest due to a known bug in FreeBSD's 32-bit emulation. The fix
+// will be included in release 11.2.
+// FIXME reenable the doc test when the CI machine gets upgraded to that release.
+// https://svnweb.freebsd.org/base?view=revision&revision=325018
+/// ```no_run
+/// # extern crate tempfile;
+/// # extern crate nix;
+/// # use nix::sys::aio::*;
+/// # use nix::sys::signal::SigevNotify;
+/// # use std::os::unix::io::AsRawFd;
+/// # use tempfile::tempfile;
+/// # fn main() {
+/// const WBUF: &[u8] = b"abcdef123456";
+/// let mut f = tempfile().unwrap();
+/// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
+/// 2, //offset
+/// WBUF,
+/// 0, //priority
+/// SigevNotify::SigevNone,
+/// LioOpcode::LIO_NOP);
+/// aiocb.write().unwrap();
+/// aio_suspend(&[&aiocb], None).expect("aio_suspend failed");
+/// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
+/// # }
+/// ```
+/// # References
+///
+/// [`aio_suspend`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_suspend.html)
pub fn aio_suspend(list: &[&AioCb], timeout: Option<TimeSpec>) -> Result<()> {
let plist = list as *const [&AioCb] as *const [*const libc::aiocb];
let p = plist as *const *const libc::aiocb;
@@ -547,8 +966,50 @@ pub fn aio_suspend(list: &[&AioCb], timeout: Option<TimeSpec>) -> Result<()> {
}
-/// Submits multiple asynchronous I/O requests with a single system call. The
-/// order in which the requests are carried out is not specified.
+/// Submits multiple asynchronous I/O requests with a single system call.
+///
+/// They are not guaranteed to complete atomically, and the order in which the
+/// requests are carried out is not specified. Reads, writes, and fsyncs may be
+/// freely mixed.
+///
+/// This function is useful for reducing the context-switch overhead of
+/// submitting many AIO operations. It can also be used with
+/// `LioMode::LIO_WAIT` to block on the result of several independent
+/// operations. Used that way, it is often useful in programs that otherwise
+/// make little use of AIO.
+///
+/// # Examples
+///
+/// Use `lio_listio` to submit an aio operation and wait for its completion. In
+/// this case, there is no need to use `aio_suspend` to wait or `AioCb#error` to
+/// poll.
+///
+/// ```
+/// # extern crate tempfile;
+/// # extern crate nix;
+/// # use nix::sys::aio::*;
+/// # use nix::sys::signal::SigevNotify;
+/// # use std::os::unix::io::AsRawFd;
+/// # use tempfile::tempfile;
+/// # fn main() {
+/// const WBUF: &[u8] = b"abcdef123456";
+/// let mut f = tempfile().unwrap();
+/// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
+/// 2, //offset
+/// WBUF,
+/// 0, //priority
+/// SigevNotify::SigevNone,
+/// LioOpcode::LIO_WRITE);
+/// lio_listio(LioMode::LIO_WAIT,
+/// &[&mut aiocb],
+/// SigevNotify::SigevNone).unwrap();
+/// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
+/// # }
+/// ```
+///
+/// # References
+///
+/// [`lio_listio`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html)
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
pub fn lio_listio(mode: LioMode, list: &[&mut AioCb],
sigev_notify: SigevNotify) -> Result<()> {