| // vim: tw=80 | 
 | //! POSIX Asynchronous I/O | 
 | //! | 
 | //! The POSIX AIO interface is used for asynchronous I/O on files and disk-like | 
 | //! devices.  It supports [`read`](struct.AioRead.html#method.new), | 
 | //! [`write`](struct.AioWrite.html#method.new), | 
 | //! [`fsync`](struct.AioFsync.html#method.new), | 
 | //! [`readv`](struct.AioReadv.html#method.new), and | 
 | //! [`writev`](struct.AioWritev.html#method.new), operations, subject to | 
 | //! platform support.  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`](trait.Aio.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. | 
 | #[cfg(target_os = "freebsd")] | 
 | use std::io::{IoSlice, IoSliceMut}; | 
 | use std::{ | 
 |     convert::TryFrom, | 
 |     fmt::{self, Debug}, | 
 |     marker::{PhantomData, PhantomPinned}, | 
 |     mem, | 
 |     os::unix::io::RawFd, | 
 |     pin::Pin, | 
 |     ptr, thread, | 
 | }; | 
 |  | 
 | use libc::off_t; | 
 | use pin_utils::unsafe_pinned; | 
 |  | 
 | use crate::{ | 
 |     errno::Errno, | 
 |     sys::{signal::*, time::TimeSpec}, | 
 |     Result, | 
 | }; | 
 |  | 
 | libc_enum! { | 
 |     /// Mode for `AioCb::fsync`.  Controls whether only data or both data and | 
 |     /// metadata are synced. | 
 |     #[repr(i32)] | 
 |     #[non_exhaustive] | 
 |     pub enum AioFsyncMode { | 
 |         /// do it like `fsync` | 
 |         O_SYNC, | 
 |         /// on supported operating systems only, do it like `fdatasync` | 
 |         #[cfg(any(apple_targets, | 
 |                   target_os = "linux", | 
 |                   netbsdlike))] | 
 |         O_DSYNC | 
 |     } | 
 |     impl TryFrom<i32> | 
 | } | 
 |  | 
 | libc_enum! { | 
 |     /// Mode for [`lio_listio`](fn.lio_listio.html) | 
 |     #[repr(i32)] | 
 |     pub enum LioMode { | 
 |         /// Requests that [`lio_listio`](fn.lio_listio.html) block until all | 
 |         /// requested operations have been completed | 
 |         LIO_WAIT, | 
 |         /// Requests that [`lio_listio`](fn.lio_listio.html) return immediately | 
 |         LIO_NOWAIT, | 
 |     } | 
 | } | 
 |  | 
 | /// 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, Eq, Hash, PartialEq)] | 
 | pub enum AioCancelStat { | 
 |     /// All outstanding requests were canceled | 
 |     AioCanceled = libc::AIO_CANCELED, | 
 |     /// Some requests were not canceled.  Their status should be checked with | 
 |     /// `AioCb::error` | 
 |     AioNotCanceled = libc::AIO_NOTCANCELED, | 
 |     /// All of the requests have already finished | 
 |     AioAllDone = libc::AIO_ALLDONE, | 
 | } | 
 |  | 
 | /// Newtype that adds Send and Sync to libc::aiocb, which contains raw pointers | 
 | #[repr(transparent)] | 
 | struct LibcAiocb(libc::aiocb); | 
 |  | 
 | unsafe impl Send for LibcAiocb {} | 
 | unsafe impl Sync for LibcAiocb {} | 
 |  | 
 | /// Base class for all AIO operations.  Should only be used directly when | 
 | /// checking for completion. | 
 | // We could create some kind of AsPinnedMut trait, and implement it for all aio | 
 | // ops, allowing the crate's users to get pinned references to `AioCb`.  That | 
 | // could save some code for things like polling methods.  But IMHO it would | 
 | // provide polymorphism at the wrong level.  Instead, the best place for | 
 | // polymorphism is at the level of `Futures`. | 
 | #[repr(C)] | 
 | struct AioCb { | 
 |     aiocb: LibcAiocb, | 
 |     /// Could this `AioCb` potentially have any in-kernel state? | 
 |     // It would be really nice to perform the in-progress check entirely at | 
 |     // compile time.  But I can't figure out how, because: | 
 |     // * Future::poll takes a `Pin<&mut self>` rather than `self`, and | 
 |     // * Rust's lack of an equivalent of C++'s Guaranteed Copy Elision means | 
 |     //   that there's no way to write an AioCb constructor that neither boxes | 
 |     //   the object itself, nor moves it during return. | 
 |     in_progress: bool, | 
 | } | 
 |  | 
 | impl AioCb { | 
 |     pin_utils::unsafe_unpinned!(aiocb: LibcAiocb); | 
 |  | 
 |     fn aio_return(mut self: Pin<&mut Self>) -> Result<usize> { | 
 |         self.in_progress = false; | 
 |         unsafe { | 
 |             let p: *mut libc::aiocb = &mut self.aiocb.0; | 
 |             Errno::result(libc::aio_return(p)) | 
 |         } | 
 |         .map(|r| r as usize) | 
 |     } | 
 |  | 
 |     fn cancel(mut self: Pin<&mut Self>) -> Result<AioCancelStat> { | 
 |         let r = unsafe { | 
 |             libc::aio_cancel(self.aiocb.0.aio_fildes, &mut self.aiocb.0) | 
 |         }; | 
 |         match r { | 
 |             libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled), | 
 |             libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled), | 
 |             libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone), | 
 |             -1 => Err(Errno::last()), | 
 |             _ => panic!("unknown aio_cancel return value"), | 
 |         } | 
 |     } | 
 |  | 
 |     fn common_init(fd: RawFd, prio: i32, sigev_notify: SigevNotify) -> Self { | 
 |         // Use mem::zeroed instead of explicitly zeroing each field, because the | 
 |         // number and name of reserved fields is OS-dependent.  On some OSes, | 
 |         // some reserved fields are used the kernel for state, and must be | 
 |         // explicitly zeroed when allocated. | 
 |         let mut a = unsafe { mem::zeroed::<libc::aiocb>() }; | 
 |         a.aio_fildes = fd; | 
 |         a.aio_reqprio = prio; | 
 |         a.aio_sigevent = SigEvent::new(sigev_notify).sigevent(); | 
 |         AioCb { | 
 |             aiocb: LibcAiocb(a), | 
 |             in_progress: false, | 
 |         } | 
 |     } | 
 |  | 
 |     fn error(self: Pin<&mut Self>) -> Result<()> { | 
 |         let r = unsafe { libc::aio_error(&self.aiocb().0) }; | 
 |         match r { | 
 |             0 => Ok(()), | 
 |             num if num > 0 => Err(Errno::from_raw(num)), | 
 |             -1 => Err(Errno::last()), | 
 |             num => panic!("unknown aio_error return value {num:?}"), | 
 |         } | 
 |     } | 
 |  | 
 |     fn in_progress(&self) -> bool { | 
 |         self.in_progress | 
 |     } | 
 |  | 
 |     fn set_in_progress(mut self: Pin<&mut Self>) { | 
 |         self.as_mut().in_progress = true; | 
 |     } | 
 |  | 
 |     /// Update the notification settings for an existing AIO operation that has | 
 |     /// not yet been submitted. | 
 |     // Takes a normal reference rather than a pinned one because this method is | 
 |     // normally called before the object needs to be pinned, that is, before | 
 |     // it's been submitted to the kernel. | 
 |     fn set_sigev_notify(&mut self, sigev_notify: SigevNotify) { | 
 |         assert!( | 
 |             !self.in_progress, | 
 |             "Can't change notification settings for an in-progress operation" | 
 |         ); | 
 |         self.aiocb.0.aio_sigevent = SigEvent::new(sigev_notify).sigevent(); | 
 |     } | 
 | } | 
 |  | 
 | impl Debug for AioCb { | 
 |     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | 
 |         fmt.debug_struct("AioCb") | 
 |             .field("aiocb", &self.aiocb.0) | 
 |             .field("in_progress", &self.in_progress) | 
 |             .finish() | 
 |     } | 
 | } | 
 |  | 
 | impl Drop for AioCb { | 
 |     /// If the `AioCb` has no remaining state in the kernel, just drop it. | 
 |     /// Otherwise, dropping constitutes a resource leak, which is an error | 
 |     fn drop(&mut self) { | 
 |         assert!( | 
 |             thread::panicking() || !self.in_progress, | 
 |             "Dropped an in-progress AioCb" | 
 |         ); | 
 |     } | 
 | } | 
 |  | 
 | /// Methods common to all AIO operations | 
 | pub trait Aio { | 
 |     /// The return type of [`Aio::aio_return`]. | 
 |     type Output; | 
 |  | 
 |     /// Retrieve return status of an asynchronous operation. | 
 |     /// | 
 |     /// Should only be called once for each operation, after [`Aio::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](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_return.html) | 
 |     fn aio_return(self: Pin<&mut Self>) -> Result<Self::Output>; | 
 |  | 
 |     /// 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. | 
 |     /// | 
 |     /// ``` | 
 |     /// # 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; | 
 |     /// let wbuf = b"CDEF"; | 
 |     /// let mut f = tempfile().unwrap(); | 
 |     /// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), | 
 |     ///     2,   //offset | 
 |     ///     &wbuf[..], | 
 |     ///     0,   //priority | 
 |     ///     SigevNotify::SigevNone)); | 
 |     /// aiocb.as_mut().submit().unwrap(); | 
 |     /// let cs = aiocb.as_mut().cancel().unwrap(); | 
 |     /// if cs == AioCancelStat::AioNotCanceled { | 
 |     ///     while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) { | 
 |     ///         thread::sleep(time::Duration::from_millis(10)); | 
 |     ///     } | 
 |     /// } | 
 |     /// // Must call `aio_return`, but ignore the result | 
 |     /// let _ = aiocb.as_mut().aio_return(); | 
 |     /// ``` | 
 |     /// | 
 |     /// # References | 
 |     /// | 
 |     /// [aio_cancel](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html) | 
 |     fn cancel(self: Pin<&mut Self>) -> Result<AioCancelStat>; | 
 |  | 
 |     /// 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. | 
 |     /// | 
 |     /// ``` | 
 |     /// # 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; | 
 |     /// const WBUF: &[u8] = b"abcdef123456"; | 
 |     /// let mut f = tempfile().unwrap(); | 
 |     /// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), | 
 |     ///     2,   //offset | 
 |     ///     WBUF, | 
 |     ///     0,   //priority | 
 |     ///     SigevNotify::SigevNone)); | 
 |     /// aiocb.as_mut().submit().unwrap(); | 
 |     /// while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) { | 
 |     ///     thread::sleep(time::Duration::from_millis(10)); | 
 |     /// } | 
 |     /// assert_eq!(aiocb.as_mut().aio_return().unwrap(), WBUF.len()); | 
 |     /// ``` | 
 |     /// | 
 |     /// # References | 
 |     /// | 
 |     /// [aio_error](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_error.html) | 
 |     fn error(self: Pin<&mut Self>) -> Result<()>; | 
 |  | 
 |     /// Returns the underlying file descriptor associated with the operation. | 
 |     fn fd(&self) -> RawFd; | 
 |  | 
 |     /// Does this operation currently have any in-kernel state? | 
 |     /// | 
 |     /// Dropping an operation that does have in-kernel state constitutes a | 
 |     /// resource leak. | 
 |     /// | 
 |     /// # Examples | 
 |     /// | 
 |     /// ``` | 
 |     /// # 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; | 
 |     /// let f = tempfile().unwrap(); | 
 |     /// let mut aiof = Box::pin(AioFsync::new(f.as_raw_fd(), AioFsyncMode::O_SYNC, | 
 |     ///     0, SigevNone)); | 
 |     /// assert!(!aiof.as_mut().in_progress()); | 
 |     /// aiof.as_mut().submit().expect("aio_fsync failed early"); | 
 |     /// assert!(aiof.as_mut().in_progress()); | 
 |     /// while (aiof.as_mut().error() == Err(Errno::EINPROGRESS)) { | 
 |     ///     thread::sleep(time::Duration::from_millis(10)); | 
 |     /// } | 
 |     /// aiof.as_mut().aio_return().expect("aio_fsync failed late"); | 
 |     /// assert!(!aiof.as_mut().in_progress()); | 
 |     /// ``` | 
 |     fn in_progress(&self) -> bool; | 
 |  | 
 |     /// Returns the priority of the `AioCb` | 
 |     fn priority(&self) -> i32; | 
 |  | 
 |     /// Update the notification settings for an existing AIO operation that has | 
 |     /// not yet been submitted. | 
 |     fn set_sigev_notify(&mut self, sev: SigevNotify); | 
 |  | 
 |     /// Returns the `SigEvent` that will be used for notification. | 
 |     fn sigevent(&self) -> SigEvent; | 
 |  | 
 |     /// Actually start the I/O operation. | 
 |     /// | 
 |     /// After calling this method and until [`Aio::aio_return`] returns `Ok`, | 
 |     /// the structure may not be moved in memory. | 
 |     fn submit(self: Pin<&mut Self>) -> Result<()>; | 
 | } | 
 |  | 
 | macro_rules! aio_methods { | 
 |     () => { | 
 |         fn cancel(self: Pin<&mut Self>) -> Result<AioCancelStat> { | 
 |             self.aiocb().cancel() | 
 |         } | 
 |  | 
 |         fn error(self: Pin<&mut Self>) -> Result<()> { | 
 |             self.aiocb().error() | 
 |         } | 
 |  | 
 |         fn fd(&self) -> RawFd { | 
 |             self.aiocb.aiocb.0.aio_fildes | 
 |         } | 
 |  | 
 |         fn in_progress(&self) -> bool { | 
 |             self.aiocb.in_progress() | 
 |         } | 
 |  | 
 |         fn priority(&self) -> i32 { | 
 |             self.aiocb.aiocb.0.aio_reqprio | 
 |         } | 
 |  | 
 |         fn set_sigev_notify(&mut self, sev: SigevNotify) { | 
 |             self.aiocb.set_sigev_notify(sev) | 
 |         } | 
 |  | 
 |         fn sigevent(&self) -> SigEvent { | 
 |             SigEvent::from(&self.aiocb.aiocb.0.aio_sigevent) | 
 |         } | 
 |     }; | 
 |     ($func:ident) => { | 
 |         aio_methods!(); | 
 |  | 
 |         fn aio_return(self: Pin<&mut Self>) -> Result<<Self as Aio>::Output> { | 
 |             self.aiocb().aio_return() | 
 |         } | 
 |  | 
 |         fn submit(mut self: Pin<&mut Self>) -> Result<()> { | 
 |             let p: *mut libc::aiocb = &mut self.as_mut().aiocb().aiocb.0; | 
 |             Errno::result({ unsafe { libc::$func(p) } }).map(|_| { | 
 |                 self.aiocb().set_in_progress(); | 
 |             }) | 
 |         } | 
 |     }; | 
 | } | 
 |  | 
 | /// An asynchronous version of `fsync(2)`. | 
 | /// | 
 | /// # References | 
 | /// | 
 | /// [aio_fsync](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_fsync.html) | 
 | /// # Examples | 
 | /// | 
 | /// ``` | 
 | /// # 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; | 
 | /// let f = tempfile().unwrap(); | 
 | /// let mut aiof = Box::pin(AioFsync::new(f.as_raw_fd(), AioFsyncMode::O_SYNC, | 
 | ///     0, SigevNone)); | 
 | /// aiof.as_mut().submit().expect("aio_fsync failed early"); | 
 | /// while (aiof.as_mut().error() == Err(Errno::EINPROGRESS)) { | 
 | ///     thread::sleep(time::Duration::from_millis(10)); | 
 | /// } | 
 | /// aiof.as_mut().aio_return().expect("aio_fsync failed late"); | 
 | /// ``` | 
 | #[derive(Debug)] | 
 | #[repr(transparent)] | 
 | pub struct AioFsync { | 
 |     aiocb: AioCb, | 
 |     _pin: PhantomPinned, | 
 | } | 
 |  | 
 | impl AioFsync { | 
 |     unsafe_pinned!(aiocb: AioCb); | 
 |  | 
 |     /// Returns the operation's fsync mode: data and metadata or data only? | 
 |     pub fn mode(&self) -> AioFsyncMode { | 
 |         AioFsyncMode::try_from(self.aiocb.aiocb.0.aio_lio_opcode).unwrap() | 
 |     } | 
 |  | 
 |     /// Create a new `AioFsync`. | 
 |     /// | 
 |     /// # Arguments | 
 |     /// | 
 |     /// * `fd`:           File descriptor to sync. | 
 |     /// * `mode`:         Whether to sync file metadata too, or just data. | 
 |     /// * `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. | 
 |     pub fn new( | 
 |         fd: RawFd, | 
 |         mode: AioFsyncMode, | 
 |         prio: i32, | 
 |         sigev_notify: SigevNotify, | 
 |     ) -> Self { | 
 |         let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); | 
 |         // To save some memory, store mode in an unused field of the AioCb. | 
 |         // True it isn't very much memory, but downstream creates will likely | 
 |         // create an enum containing this and other AioCb variants and pack | 
 |         // those enums into data structures like Vec, so it adds up. | 
 |         aiocb.aiocb.0.aio_lio_opcode = mode as libc::c_int; | 
 |         AioFsync { | 
 |             aiocb, | 
 |             _pin: PhantomPinned, | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | impl Aio for AioFsync { | 
 |     type Output = (); | 
 |  | 
 |     aio_methods!(); | 
 |  | 
 |     fn aio_return(self: Pin<&mut Self>) -> Result<()> { | 
 |         self.aiocb().aio_return().map(drop) | 
 |     } | 
 |  | 
 |     fn submit(mut self: Pin<&mut Self>) -> Result<()> { | 
 |         let aiocb = &mut self.as_mut().aiocb().aiocb.0; | 
 |         let mode = mem::replace(&mut aiocb.aio_lio_opcode, 0); | 
 |         let p: *mut libc::aiocb = aiocb; | 
 |         Errno::result(unsafe { libc::aio_fsync(mode, p) }).map(|_| { | 
 |             self.aiocb().set_in_progress(); | 
 |         }) | 
 |     } | 
 | } | 
 |  | 
 | // AioFsync does not need AsMut, since it can't be used with lio_listio | 
 |  | 
 | impl AsRef<libc::aiocb> for AioFsync { | 
 |     fn as_ref(&self) -> &libc::aiocb { | 
 |         &self.aiocb.aiocb.0 | 
 |     } | 
 | } | 
 |  | 
 | /// Asynchronously reads from a file descriptor into a buffer | 
 | /// | 
 | /// # References | 
 | /// | 
 | /// [aio_read](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_read.html) | 
 | /// | 
 | /// # Examples | 
 | /// | 
 | /// | 
 | /// ``` | 
 | /// # 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; | 
 | /// 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 aior = Box::pin( | 
 | ///         AioRead::new( | 
 | ///             f.as_raw_fd(), | 
 | ///             2,   //offset | 
 | ///             &mut rbuf, | 
 | ///             0,   //priority | 
 | ///             SigevNotify::SigevNone | 
 | ///         ) | 
 | ///     ); | 
 | ///     aior.as_mut().submit().unwrap(); | 
 | ///     while (aior.as_mut().error() == Err(Errno::EINPROGRESS)) { | 
 | ///         thread::sleep(time::Duration::from_millis(10)); | 
 | ///     } | 
 | ///     assert_eq!(aior.as_mut().aio_return().unwrap(), LEN); | 
 | /// } | 
 | /// assert_eq!(rbuf, b"cdef"); | 
 | /// ``` | 
 | #[derive(Debug)] | 
 | #[repr(transparent)] | 
 | pub struct AioRead<'a> { | 
 |     aiocb: AioCb, | 
 |     _data: PhantomData<&'a [u8]>, | 
 |     _pin: PhantomPinned, | 
 | } | 
 |  | 
 | impl<'a> AioRead<'a> { | 
 |     unsafe_pinned!(aiocb: AioCb); | 
 |  | 
 |     /// Returns the requested length of the aio operation in bytes | 
 |     /// | 
 |     /// This method returns the *requested* length of the operation.  To get the | 
 |     /// number of bytes actually read or written by a completed operation, use | 
 |     /// `aio_return` instead. | 
 |     pub fn nbytes(&self) -> usize { | 
 |         self.aiocb.aiocb.0.aio_nbytes | 
 |     } | 
 |  | 
 |     /// Create a new `AioRead`, placing the data in a mutable slice. | 
 |     /// | 
 |     /// # Arguments | 
 |     /// | 
 |     /// * `fd`:           File descriptor to read from | 
 |     /// * `offs`:         File offset | 
 |     /// * `buf`:          A memory buffer.  It must outlive the `AioRead`. | 
 |     /// * `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. | 
 |     pub fn new( | 
 |         fd: RawFd, | 
 |         offs: off_t, | 
 |         buf: &'a mut [u8], | 
 |         prio: i32, | 
 |         sigev_notify: SigevNotify, | 
 |     ) -> Self { | 
 |         let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); | 
 |         aiocb.aiocb.0.aio_nbytes = buf.len(); | 
 |         aiocb.aiocb.0.aio_buf = buf.as_mut_ptr().cast(); | 
 |         aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READ; | 
 |         aiocb.aiocb.0.aio_offset = offs; | 
 |         AioRead { | 
 |             aiocb, | 
 |             _data: PhantomData, | 
 |             _pin: PhantomPinned, | 
 |         } | 
 |     } | 
 |  | 
 |     /// Returns the file offset of the operation. | 
 |     pub fn offset(&self) -> off_t { | 
 |         self.aiocb.aiocb.0.aio_offset | 
 |     } | 
 | } | 
 |  | 
 | impl<'a> Aio for AioRead<'a> { | 
 |     type Output = usize; | 
 |  | 
 |     aio_methods!(aio_read); | 
 | } | 
 |  | 
 | impl<'a> AsMut<libc::aiocb> for AioRead<'a> { | 
 |     fn as_mut(&mut self) -> &mut libc::aiocb { | 
 |         &mut self.aiocb.aiocb.0 | 
 |     } | 
 | } | 
 |  | 
 | impl<'a> AsRef<libc::aiocb> for AioRead<'a> { | 
 |     fn as_ref(&self) -> &libc::aiocb { | 
 |         &self.aiocb.aiocb.0 | 
 |     } | 
 | } | 
 |  | 
 | /// Asynchronously reads from a file descriptor into a scatter/gather list of buffers. | 
 | /// | 
 | /// # References | 
 | /// | 
 | /// [aio_readv](https://www.freebsd.org/cgi/man.cgi?query=aio_readv) | 
 | /// | 
 | /// # Examples | 
 | /// | 
 | /// | 
 | #[cfg_attr(fbsd14, doc = " ```")] | 
 | #[cfg_attr(not(fbsd14), doc = " ```no_run")] | 
 | /// # use nix::errno::Errno; | 
 | /// # use nix::Error; | 
 | /// # use nix::sys::aio::*; | 
 | /// # use nix::sys::signal::SigevNotify; | 
 | /// # use std::{thread, time}; | 
 | /// # use std::io::{IoSliceMut, Write}; | 
 | /// # use std::os::unix::io::AsRawFd; | 
 | /// # use tempfile::tempfile; | 
 | /// const INITIAL: &[u8] = b"abcdef123456"; | 
 | /// let mut rbuf0 = vec![0; 4]; | 
 | /// let mut rbuf1 = vec![0; 2]; | 
 | /// let expected_len = rbuf0.len() + rbuf1.len(); | 
 | /// let mut rbufs = [IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)]; | 
 | /// let mut f = tempfile().unwrap(); | 
 | /// f.write_all(INITIAL).unwrap(); | 
 | /// { | 
 | ///     let mut aior = Box::pin( | 
 | ///         AioReadv::new( | 
 | ///             f.as_raw_fd(), | 
 | ///             2,   //offset | 
 | ///             &mut rbufs, | 
 | ///             0,   //priority | 
 | ///             SigevNotify::SigevNone | 
 | ///         ) | 
 | ///     ); | 
 | ///     aior.as_mut().submit().unwrap(); | 
 | ///     while (aior.as_mut().error() == Err(Errno::EINPROGRESS)) { | 
 | ///         thread::sleep(time::Duration::from_millis(10)); | 
 | ///     } | 
 | ///     assert_eq!(aior.as_mut().aio_return().unwrap(), expected_len); | 
 | /// } | 
 | /// assert_eq!(rbuf0, b"cdef"); | 
 | /// assert_eq!(rbuf1, b"12"); | 
 | /// ``` | 
 | #[cfg(target_os = "freebsd")] | 
 | #[derive(Debug)] | 
 | #[repr(transparent)] | 
 | pub struct AioReadv<'a> { | 
 |     aiocb: AioCb, | 
 |     _data: PhantomData<&'a [&'a [u8]]>, | 
 |     _pin: PhantomPinned, | 
 | } | 
 |  | 
 | #[cfg(target_os = "freebsd")] | 
 | impl<'a> AioReadv<'a> { | 
 |     unsafe_pinned!(aiocb: AioCb); | 
 |  | 
 |     /// Returns the number of buffers the operation will read into. | 
 |     pub fn iovlen(&self) -> usize { | 
 |         self.aiocb.aiocb.0.aio_nbytes | 
 |     } | 
 |  | 
 |     /// Create a new `AioReadv`, placing the data in a list of mutable slices. | 
 |     /// | 
 |     /// # Arguments | 
 |     /// | 
 |     /// * `fd`:           File descriptor to read from | 
 |     /// * `offs`:         File offset | 
 |     /// * `bufs`:         A scatter/gather list of memory buffers.  They must | 
 |     ///                   outlive the `AioReadv`. | 
 |     /// * `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. | 
 |     pub fn new( | 
 |         fd: RawFd, | 
 |         offs: off_t, | 
 |         bufs: &mut [IoSliceMut<'a>], | 
 |         prio: i32, | 
 |         sigev_notify: SigevNotify, | 
 |     ) -> Self { | 
 |         let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); | 
 |         // In vectored mode, aio_nbytes stores the length of the iovec array, | 
 |         // not the byte count. | 
 |         aiocb.aiocb.0.aio_nbytes = bufs.len(); | 
 |         aiocb.aiocb.0.aio_buf = bufs.as_mut_ptr().cast(); | 
 |         aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READV; | 
 |         aiocb.aiocb.0.aio_offset = offs; | 
 |         AioReadv { | 
 |             aiocb, | 
 |             _data: PhantomData, | 
 |             _pin: PhantomPinned, | 
 |         } | 
 |     } | 
 |  | 
 |     /// Returns the file offset of the operation. | 
 |     pub fn offset(&self) -> off_t { | 
 |         self.aiocb.aiocb.0.aio_offset | 
 |     } | 
 | } | 
 |  | 
 | #[cfg(target_os = "freebsd")] | 
 | impl<'a> Aio for AioReadv<'a> { | 
 |     type Output = usize; | 
 |  | 
 |     aio_methods!(aio_readv); | 
 | } | 
 |  | 
 | #[cfg(target_os = "freebsd")] | 
 | impl<'a> AsMut<libc::aiocb> for AioReadv<'a> { | 
 |     fn as_mut(&mut self) -> &mut libc::aiocb { | 
 |         &mut self.aiocb.aiocb.0 | 
 |     } | 
 | } | 
 |  | 
 | #[cfg(target_os = "freebsd")] | 
 | impl<'a> AsRef<libc::aiocb> for AioReadv<'a> { | 
 |     fn as_ref(&self) -> &libc::aiocb { | 
 |         &self.aiocb.aiocb.0 | 
 |     } | 
 | } | 
 |  | 
 | /// Asynchronously writes from a buffer to a file descriptor | 
 | /// | 
 | /// # References | 
 | /// | 
 | /// [aio_write](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_write.html) | 
 | /// | 
 | /// # Examples | 
 | /// | 
 | /// ``` | 
 | /// # 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; | 
 | /// const WBUF: &[u8] = b"abcdef123456"; | 
 | /// let mut f = tempfile().unwrap(); | 
 | /// let mut aiow = Box::pin( | 
 | ///     AioWrite::new( | 
 | ///         f.as_raw_fd(), | 
 | ///         2,   //offset | 
 | ///         WBUF, | 
 | ///         0,   //priority | 
 | ///         SigevNotify::SigevNone | 
 | ///     ) | 
 | /// ); | 
 | /// aiow.as_mut().submit().unwrap(); | 
 | /// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) { | 
 | ///     thread::sleep(time::Duration::from_millis(10)); | 
 | /// } | 
 | /// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); | 
 | /// ``` | 
 | #[derive(Debug)] | 
 | #[repr(transparent)] | 
 | pub struct AioWrite<'a> { | 
 |     aiocb: AioCb, | 
 |     _data: PhantomData<&'a [u8]>, | 
 |     _pin: PhantomPinned, | 
 | } | 
 |  | 
 | impl<'a> AioWrite<'a> { | 
 |     unsafe_pinned!(aiocb: AioCb); | 
 |  | 
 |     /// Returns the requested length of the aio operation in bytes | 
 |     /// | 
 |     /// This method returns the *requested* length of the operation.  To get the | 
 |     /// number of bytes actually read or written by a completed operation, use | 
 |     /// `aio_return` instead. | 
 |     pub fn nbytes(&self) -> usize { | 
 |         self.aiocb.aiocb.0.aio_nbytes | 
 |     } | 
 |  | 
 |     /// Construct a new `AioWrite`. | 
 |     /// | 
 |     /// # Arguments | 
 |     /// | 
 |     /// * `fd`:           File descriptor to write to | 
 |     /// * `offs`:         File offset | 
 |     /// * `buf`:          A memory buffer.  It must outlive the `AioWrite`. | 
 |     /// * `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. | 
 |     pub fn new( | 
 |         fd: RawFd, | 
 |         offs: off_t, | 
 |         buf: &'a [u8], | 
 |         prio: i32, | 
 |         sigev_notify: SigevNotify, | 
 |     ) -> Self { | 
 |         let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); | 
 |         aiocb.aiocb.0.aio_nbytes = buf.len(); | 
 |         // casting an immutable buffer to a mutable pointer looks unsafe, | 
 |         // but technically its only unsafe to dereference it, not to create | 
 |         // it.  Type Safety guarantees that we'll never pass aiocb to | 
 |         // aio_read or aio_readv. | 
 |         aiocb.aiocb.0.aio_buf = buf.as_ptr().cast_mut().cast(); | 
 |         aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITE; | 
 |         aiocb.aiocb.0.aio_offset = offs; | 
 |         AioWrite { | 
 |             aiocb, | 
 |             _data: PhantomData, | 
 |             _pin: PhantomPinned, | 
 |         } | 
 |     } | 
 |  | 
 |     /// Returns the file offset of the operation. | 
 |     pub fn offset(&self) -> off_t { | 
 |         self.aiocb.aiocb.0.aio_offset | 
 |     } | 
 | } | 
 |  | 
 | impl<'a> Aio for AioWrite<'a> { | 
 |     type Output = usize; | 
 |  | 
 |     aio_methods!(aio_write); | 
 | } | 
 |  | 
 | impl<'a> AsMut<libc::aiocb> for AioWrite<'a> { | 
 |     fn as_mut(&mut self) -> &mut libc::aiocb { | 
 |         &mut self.aiocb.aiocb.0 | 
 |     } | 
 | } | 
 |  | 
 | impl<'a> AsRef<libc::aiocb> for AioWrite<'a> { | 
 |     fn as_ref(&self) -> &libc::aiocb { | 
 |         &self.aiocb.aiocb.0 | 
 |     } | 
 | } | 
 |  | 
 | /// Asynchronously writes from a scatter/gather list of buffers to a file descriptor. | 
 | /// | 
 | /// # References | 
 | /// | 
 | /// [aio_writev](https://www.freebsd.org/cgi/man.cgi?query=aio_writev) | 
 | /// | 
 | /// # Examples | 
 | /// | 
 | #[cfg_attr(fbsd14, doc = " ```")] | 
 | #[cfg_attr(not(fbsd14), doc = " ```no_run")] | 
 | /// # use nix::errno::Errno; | 
 | /// # use nix::Error; | 
 | /// # use nix::sys::aio::*; | 
 | /// # use nix::sys::signal::SigevNotify; | 
 | /// # use std::{thread, time}; | 
 | /// # use std::io::IoSlice; | 
 | /// # use std::os::unix::io::AsRawFd; | 
 | /// # use tempfile::tempfile; | 
 | /// const wbuf0: &[u8] = b"abcdef"; | 
 | /// const wbuf1: &[u8] = b"123456"; | 
 | /// let len = wbuf0.len() + wbuf1.len(); | 
 | /// let wbufs = [IoSlice::new(wbuf0), IoSlice::new(wbuf1)]; | 
 | /// let mut f = tempfile().unwrap(); | 
 | /// let mut aiow = Box::pin( | 
 | ///     AioWritev::new( | 
 | ///         f.as_raw_fd(), | 
 | ///         2,   //offset | 
 | ///         &wbufs, | 
 | ///         0,   //priority | 
 | ///         SigevNotify::SigevNone | 
 | ///     ) | 
 | /// ); | 
 | /// aiow.as_mut().submit().unwrap(); | 
 | /// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) { | 
 | ///     thread::sleep(time::Duration::from_millis(10)); | 
 | /// } | 
 | /// assert_eq!(aiow.as_mut().aio_return().unwrap(), len); | 
 | /// ``` | 
 | #[cfg(target_os = "freebsd")] | 
 | #[derive(Debug)] | 
 | #[repr(transparent)] | 
 | pub struct AioWritev<'a> { | 
 |     aiocb: AioCb, | 
 |     _data: PhantomData<&'a [&'a [u8]]>, | 
 |     _pin: PhantomPinned, | 
 | } | 
 |  | 
 | #[cfg(target_os = "freebsd")] | 
 | impl<'a> AioWritev<'a> { | 
 |     unsafe_pinned!(aiocb: AioCb); | 
 |  | 
 |     /// Returns the number of buffers the operation will read into. | 
 |     pub fn iovlen(&self) -> usize { | 
 |         self.aiocb.aiocb.0.aio_nbytes | 
 |     } | 
 |  | 
 |     /// Construct a new `AioWritev`. | 
 |     /// | 
 |     /// # Arguments | 
 |     /// | 
 |     /// * `fd`:           File descriptor to write to | 
 |     /// * `offs`:         File offset | 
 |     /// * `bufs`:         A scatter/gather list of memory buffers.  They must | 
 |     ///                   outlive the `AioWritev`. | 
 |     /// * `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. | 
 |     pub fn new( | 
 |         fd: RawFd, | 
 |         offs: off_t, | 
 |         bufs: &[IoSlice<'a>], | 
 |         prio: i32, | 
 |         sigev_notify: SigevNotify, | 
 |     ) -> Self { | 
 |         let mut aiocb = AioCb::common_init(fd, prio, sigev_notify); | 
 |         // In vectored mode, aio_nbytes stores the length of the iovec array, | 
 |         // not the byte count. | 
 |         aiocb.aiocb.0.aio_nbytes = bufs.len(); | 
 |         // casting an immutable buffer to a mutable pointer looks unsafe, | 
 |         // but technically its only unsafe to dereference it, not to create | 
 |         // it.  Type Safety guarantees that we'll never pass aiocb to | 
 |         // aio_read or aio_readv. | 
 |         aiocb.aiocb.0.aio_buf = bufs.as_ptr().cast_mut().cast(); | 
 |         aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITEV; | 
 |         aiocb.aiocb.0.aio_offset = offs; | 
 |         AioWritev { | 
 |             aiocb, | 
 |             _data: PhantomData, | 
 |             _pin: PhantomPinned, | 
 |         } | 
 |     } | 
 |  | 
 |     /// Returns the file offset of the operation. | 
 |     pub fn offset(&self) -> off_t { | 
 |         self.aiocb.aiocb.0.aio_offset | 
 |     } | 
 | } | 
 |  | 
 | #[cfg(target_os = "freebsd")] | 
 | impl<'a> Aio for AioWritev<'a> { | 
 |     type Output = usize; | 
 |  | 
 |     aio_methods!(aio_writev); | 
 | } | 
 |  | 
 | #[cfg(target_os = "freebsd")] | 
 | impl<'a> AsMut<libc::aiocb> for AioWritev<'a> { | 
 |     fn as_mut(&mut self) -> &mut libc::aiocb { | 
 |         &mut self.aiocb.aiocb.0 | 
 |     } | 
 | } | 
 |  | 
 | #[cfg(target_os = "freebsd")] | 
 | impl<'a> AsRef<libc::aiocb> for AioWritev<'a> { | 
 |     fn as_ref(&self) -> &libc::aiocb { | 
 |         &self.aiocb.aiocb.0 | 
 |     } | 
 | } | 
 |  | 
 | /// Cancels outstanding AIO requests for a given file descriptor. | 
 | /// | 
 | /// # Examples | 
 | /// | 
 | /// Issue an aio operation, then cancel all outstanding operations on that file | 
 | /// descriptor. | 
 | /// | 
 | /// ``` | 
 | /// # 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; | 
 | /// let wbuf = b"CDEF"; | 
 | /// let mut f = tempfile().unwrap(); | 
 | /// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), | 
 | ///     2,   //offset | 
 | ///     &wbuf[..], | 
 | ///     0,   //priority | 
 | ///     SigevNotify::SigevNone)); | 
 | /// aiocb.as_mut().submit().unwrap(); | 
 | /// let cs = aio_cancel_all(f.as_raw_fd()).unwrap(); | 
 | /// if cs == AioCancelStat::AioNotCanceled { | 
 | ///     while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) { | 
 | ///         thread::sleep(time::Duration::from_millis(10)); | 
 | ///     } | 
 | /// } | 
 | /// // Must call `aio_return`, but ignore the result | 
 | /// let _ = aiocb.as_mut().aio_return(); | 
 | /// ``` | 
 | /// | 
 | /// # References | 
 | /// | 
 | /// [`aio_cancel`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html) | 
 | pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> { | 
 |     match unsafe { libc::aio_cancel(fd, ptr::null_mut()) } { | 
 |         libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled), | 
 |         libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled), | 
 |         libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone), | 
 |         -1 => Err(Errno::last()), | 
 |         _ => panic!("unknown aio_cancel return value"), | 
 |     } | 
 | } | 
 |  | 
 | /// Suspends the calling process until at least one of the specified operations | 
 | /// have 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. | 
 | /// | 
 | /// ``` | 
 | /// # use nix::sys::aio::*; | 
 | /// # use nix::sys::signal::SigevNotify; | 
 | /// # use std::os::unix::io::AsRawFd; | 
 | /// # use tempfile::tempfile; | 
 | /// const WBUF: &[u8] = b"abcdef123456"; | 
 | /// let mut f = tempfile().unwrap(); | 
 | /// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(), | 
 | ///     2,   //offset | 
 | ///     WBUF, | 
 | ///     0,   //priority | 
 | ///     SigevNotify::SigevNone)); | 
 | /// aiocb.as_mut().submit().unwrap(); | 
 | /// aio_suspend(&[&*aiocb], None).expect("aio_suspend failed"); | 
 | /// assert_eq!(aiocb.as_mut().aio_return().unwrap() as usize, WBUF.len()); | 
 | /// ``` | 
 | /// # References | 
 | /// | 
 | /// [`aio_suspend`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_suspend.html) | 
 | pub fn aio_suspend( | 
 |     list: &[&dyn AsRef<libc::aiocb>], | 
 |     timeout: Option<TimeSpec>, | 
 | ) -> Result<()> { | 
 |     // Note that this allocation could be eliminated by making the argument | 
 |     // generic, and accepting arguments like &[AioWrite].  But that would | 
 |     // prevent using aio_suspend to wait on a heterogeneous list of mixed | 
 |     // operations. | 
 |     let v = list | 
 |         .iter() | 
 |         .map(|x| x.as_ref() as *const libc::aiocb) | 
 |         .collect::<Vec<*const libc::aiocb>>(); | 
 |     let p = v.as_ptr(); | 
 |     let timep = match timeout { | 
 |         None => ptr::null::<libc::timespec>(), | 
 |         Some(x) => x.as_ref() as *const libc::timespec, | 
 |     }; | 
 |     Errno::result(unsafe { libc::aio_suspend(p, list.len() as i32, timep) }) | 
 |         .map(drop) | 
 | } | 
 |  | 
 | /// 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, and writes may be freely | 
 | /// mixed. | 
 | /// | 
 | /// # 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 `error` to poll. | 
 | /// This mode is useful for otherwise-synchronous programs that want to execute | 
 | /// a handful of I/O operations in parallel. | 
 | /// ``` | 
 | /// # use std::os::unix::io::AsRawFd; | 
 | /// # use nix::sys::aio::*; | 
 | /// # use nix::sys::signal::SigevNotify; | 
 | /// # use tempfile::tempfile; | 
 | /// const WBUF: &[u8] = b"abcdef123456"; | 
 | /// let mut f = tempfile().unwrap(); | 
 | /// let mut aiow = Box::pin(AioWrite::new( | 
 | ///     f.as_raw_fd(), | 
 | ///     2,      // offset | 
 | ///     WBUF, | 
 | ///     0,      // priority | 
 | ///     SigevNotify::SigevNone | 
 | /// )); | 
 | /// lio_listio(LioMode::LIO_WAIT, &mut[aiow.as_mut()], SigevNotify::SigevNone) | 
 | ///     .unwrap(); | 
 | /// // At this point, we are guaranteed that aiow is complete. | 
 | /// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); | 
 | /// ``` | 
 | /// | 
 | /// Use `lio_listio` to submit multiple asynchronous operations with a single | 
 | /// syscall, but receive notification individually.  This is an efficient | 
 | /// technique for reducing overall context-switch overhead, especially when | 
 | /// combined with kqueue. | 
 | /// ``` | 
 | /// # use std::os::unix::io::AsRawFd; | 
 | /// # use std::thread; | 
 | /// # use std::time; | 
 | /// # use nix::errno::Errno; | 
 | /// # use nix::sys::aio::*; | 
 | /// # use nix::sys::signal::SigevNotify; | 
 | /// # use tempfile::tempfile; | 
 | /// const WBUF: &[u8] = b"abcdef123456"; | 
 | /// let mut f = tempfile().unwrap(); | 
 | /// let mut aiow = Box::pin(AioWrite::new( | 
 | ///     f.as_raw_fd(), | 
 | ///     2,      // offset | 
 | ///     WBUF, | 
 | ///     0,      // priority | 
 | ///     SigevNotify::SigevNone | 
 | /// )); | 
 | /// lio_listio(LioMode::LIO_NOWAIT, &mut[aiow.as_mut()], SigevNotify::SigevNone) | 
 | ///     .unwrap(); | 
 | /// // We must wait for the completion of each individual operation | 
 | /// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) { | 
 | ///     thread::sleep(time::Duration::from_millis(10)); | 
 | /// } | 
 | /// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); | 
 | /// ``` | 
 | /// | 
 | /// Use `lio_listio` to submit multiple operations, and receive notification | 
 | /// only when all of them are complete.  This can be useful when there is some | 
 | /// logical relationship between the operations.  But beware!  Errors or system | 
 | /// resource limitations may cause `lio_listio` to return `EIO`, `EAGAIN`, or | 
 | /// `EINTR`, in which case some but not all operations may have been submitted. | 
 | /// In that case, you must check the status of each individual operation, and | 
 | /// possibly resubmit some. | 
 | /// ``` | 
 | /// # use libc::c_int; | 
 | /// # use std::os::unix::io::AsRawFd; | 
 | /// # use std::sync::atomic::{AtomicBool, Ordering}; | 
 | /// # use std::thread; | 
 | /// # use std::time; | 
 | /// # use nix::errno::Errno; | 
 | /// # use nix::sys::aio::*; | 
 | /// # use nix::sys::signal::*; | 
 | /// # use tempfile::tempfile; | 
 | /// pub static SIGNALED: AtomicBool = AtomicBool::new(false); | 
 | /// | 
 | /// extern fn sigfunc(_: c_int) { | 
 | ///     SIGNALED.store(true, Ordering::Relaxed); | 
 | /// } | 
 | /// let sa = SigAction::new(SigHandler::Handler(sigfunc), | 
 | ///                         SaFlags::SA_RESETHAND, | 
 | ///                         SigSet::empty()); | 
 | /// SIGNALED.store(false, Ordering::Relaxed); | 
 | /// unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap(); | 
 | /// | 
 | /// const WBUF: &[u8] = b"abcdef123456"; | 
 | /// let mut f = tempfile().unwrap(); | 
 | /// let mut aiow = Box::pin(AioWrite::new( | 
 | ///     f.as_raw_fd(), | 
 | ///     2,      // offset | 
 | ///     WBUF, | 
 | ///     0,      // priority | 
 | ///     SigevNotify::SigevNone | 
 | /// )); | 
 | /// let sev = SigevNotify::SigevSignal { signal: Signal::SIGUSR2, si_value: 0 }; | 
 | /// lio_listio(LioMode::LIO_NOWAIT, &mut[aiow.as_mut()], sev).unwrap(); | 
 | /// while !SIGNALED.load(Ordering::Relaxed) { | 
 | ///     thread::sleep(time::Duration::from_millis(10)); | 
 | /// } | 
 | /// // At this point, since `lio_listio` returned success and delivered its | 
 | /// // notification, we know that all operations are complete. | 
 | /// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len()); | 
 | /// ``` | 
 | #[deprecated( | 
 |     since = "0.27.0", | 
 |     note = "https://github.com/nix-rust/nix/issues/2017" | 
 | )] | 
 | pub fn lio_listio( | 
 |     mode: LioMode, | 
 |     list: &mut [Pin<&mut dyn AsMut<libc::aiocb>>], | 
 |     sigev_notify: SigevNotify, | 
 | ) -> Result<()> { | 
 |     let p = list as *mut [Pin<&mut dyn AsMut<libc::aiocb>>] | 
 |         as *mut [*mut libc::aiocb] as *mut *mut libc::aiocb; | 
 |     let sigev = SigEvent::new(sigev_notify); | 
 |     let sigevp = &mut sigev.sigevent() as *mut libc::sigevent; | 
 |     Errno::result(unsafe { | 
 |         libc::lio_listio(mode as i32, p, list.len() as i32, sigevp) | 
 |     }) | 
 |     .map(drop) | 
 | } |