1 // vim: tw=80
2 //! POSIX Asynchronous I/O
3 //!
4 //! The POSIX AIO interface is used for asynchronous I/O on files and disk-like
5 //! devices.  It supports [`read`](struct.AioRead.html#method.new),
6 //! [`write`](struct.AioWrite.html#method.new),
7 //! [`fsync`](struct.AioFsync.html#method.new),
8 //! [`readv`](struct.AioReadv.html#method.new), and
9 //! [`writev`](struct.AioWritev.html#method.new), operations, subject to
10 //! platform support.  Completion
11 //! notifications can optionally be delivered via
12 //! [signals](../signal/enum.SigevNotify.html#variant.SigevSignal), via the
13 //! [`aio_suspend`](fn.aio_suspend.html) function, or via polling.  Some
14 //! platforms support other completion
15 //! notifications, such as
16 //! [kevent](../signal/enum.SigevNotify.html#variant.SigevKevent).
17 //!
18 //! Multiple operations may be submitted in a batch with
19 //! [`lio_listio`](fn.lio_listio.html), though the standard does not guarantee
20 //! that they will be executed atomically.
21 //!
22 //! Outstanding operations may be cancelled with
23 //! [`cancel`](trait.Aio.html#method.cancel) or
24 //! [`aio_cancel_all`](fn.aio_cancel_all.html), though the operating system may
25 //! not support this for all filesystems and devices.
26 #[cfg(target_os = "freebsd")]
27 use std::io::{IoSlice, IoSliceMut};
28 use std::{
29     convert::TryFrom,
30     fmt::{self, Debug},
31     marker::{PhantomData, PhantomPinned},
32     mem,
33     os::unix::io::RawFd,
34     pin::Pin,
35     ptr, thread,
36 };
37 
38 use libc::off_t;
39 use pin_utils::unsafe_pinned;
40 
41 use crate::{
42     errno::Errno,
43     sys::{signal::*, time::TimeSpec},
44     Result,
45 };
46 
47 libc_enum! {
48     /// Mode for `AioCb::fsync`.  Controls whether only data or both data and
49     /// metadata are synced.
50     #[repr(i32)]
51     #[non_exhaustive]
52     pub enum AioFsyncMode {
53         /// do it like `fsync`
54         O_SYNC,
55         /// on supported operating systems only, do it like `fdatasync`
56         #[cfg(any(apple_targets,
57                   target_os = "linux",
58                   netbsdlike))]
59         O_DSYNC
60     }
61     impl TryFrom<i32>
62 }
63 
64 libc_enum! {
65     /// Mode for [`lio_listio`](fn.lio_listio.html)
66     #[repr(i32)]
67     pub enum LioMode {
68         /// Requests that [`lio_listio`](fn.lio_listio.html) block until all
69         /// requested operations have been completed
70         LIO_WAIT,
71         /// Requests that [`lio_listio`](fn.lio_listio.html) return immediately
72         LIO_NOWAIT,
73     }
74 }
75 
76 /// Return values for [`AioCb::cancel`](struct.AioCb.html#method.cancel) and
77 /// [`aio_cancel_all`](fn.aio_cancel_all.html)
78 #[repr(i32)]
79 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
80 pub enum AioCancelStat {
81     /// All outstanding requests were canceled
82     AioCanceled = libc::AIO_CANCELED,
83     /// Some requests were not canceled.  Their status should be checked with
84     /// `AioCb::error`
85     AioNotCanceled = libc::AIO_NOTCANCELED,
86     /// All of the requests have already finished
87     AioAllDone = libc::AIO_ALLDONE,
88 }
89 
90 /// Newtype that adds Send and Sync to libc::aiocb, which contains raw pointers
91 #[repr(transparent)]
92 struct LibcAiocb(libc::aiocb);
93 
94 unsafe impl Send for LibcAiocb {}
95 unsafe impl Sync for LibcAiocb {}
96 
97 /// Base class for all AIO operations.  Should only be used directly when
98 /// checking for completion.
99 // We could create some kind of AsPinnedMut trait, and implement it for all aio
100 // ops, allowing the crate's users to get pinned references to `AioCb`.  That
101 // could save some code for things like polling methods.  But IMHO it would
102 // provide polymorphism at the wrong level.  Instead, the best place for
103 // polymorphism is at the level of `Futures`.
104 #[repr(C)]
105 struct AioCb {
106     aiocb: LibcAiocb,
107     /// Could this `AioCb` potentially have any in-kernel state?
108     // It would be really nice to perform the in-progress check entirely at
109     // compile time.  But I can't figure out how, because:
110     // * Future::poll takes a `Pin<&mut self>` rather than `self`, and
111     // * Rust's lack of an equivalent of C++'s Guaranteed Copy Elision means
112     //   that there's no way to write an AioCb constructor that neither boxes
113     //   the object itself, nor moves it during return.
114     in_progress: bool,
115 }
116 
117 impl AioCb {
118     pin_utils::unsafe_unpinned!(aiocb: LibcAiocb);
119 
aio_return(mut self: Pin<&mut Self>) -> Result<usize>120     fn aio_return(mut self: Pin<&mut Self>) -> Result<usize> {
121         self.in_progress = false;
122         unsafe {
123             let p: *mut libc::aiocb = &mut self.aiocb.0;
124             Errno::result(libc::aio_return(p))
125         }
126         .map(|r| r as usize)
127     }
128 
cancel(mut self: Pin<&mut Self>) -> Result<AioCancelStat>129     fn cancel(mut self: Pin<&mut Self>) -> Result<AioCancelStat> {
130         let r = unsafe {
131             libc::aio_cancel(self.aiocb.0.aio_fildes, &mut self.aiocb.0)
132         };
133         match r {
134             libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled),
135             libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled),
136             libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone),
137             -1 => Err(Errno::last()),
138             _ => panic!("unknown aio_cancel return value"),
139         }
140     }
141 
common_init(fd: RawFd, prio: i32, sigev_notify: SigevNotify) -> Self142     fn common_init(fd: RawFd, prio: i32, sigev_notify: SigevNotify) -> Self {
143         // Use mem::zeroed instead of explicitly zeroing each field, because the
144         // number and name of reserved fields is OS-dependent.  On some OSes,
145         // some reserved fields are used the kernel for state, and must be
146         // explicitly zeroed when allocated.
147         let mut a = unsafe { mem::zeroed::<libc::aiocb>() };
148         a.aio_fildes = fd;
149         a.aio_reqprio = prio;
150         a.aio_sigevent = SigEvent::new(sigev_notify).sigevent();
151         AioCb {
152             aiocb: LibcAiocb(a),
153             in_progress: false,
154         }
155     }
156 
error(self: Pin<&mut Self>) -> Result<()>157     fn error(self: Pin<&mut Self>) -> Result<()> {
158         let r = unsafe { libc::aio_error(&self.aiocb().0) };
159         match r {
160             0 => Ok(()),
161             num if num > 0 => Err(Errno::from_raw(num)),
162             -1 => Err(Errno::last()),
163             num => panic!("unknown aio_error return value {num:?}"),
164         }
165     }
166 
in_progress(&self) -> bool167     fn in_progress(&self) -> bool {
168         self.in_progress
169     }
170 
set_in_progress(mut self: Pin<&mut Self>)171     fn set_in_progress(mut self: Pin<&mut Self>) {
172         self.as_mut().in_progress = true;
173     }
174 
175     /// Update the notification settings for an existing AIO operation that has
176     /// not yet been submitted.
177     // Takes a normal reference rather than a pinned one because this method is
178     // normally called before the object needs to be pinned, that is, before
179     // it's been submitted to the kernel.
set_sigev_notify(&mut self, sigev_notify: SigevNotify)180     fn set_sigev_notify(&mut self, sigev_notify: SigevNotify) {
181         assert!(
182             !self.in_progress,
183             "Can't change notification settings for an in-progress operation"
184         );
185         self.aiocb.0.aio_sigevent = SigEvent::new(sigev_notify).sigevent();
186     }
187 }
188 
189 impl Debug for AioCb {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result190     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
191         fmt.debug_struct("AioCb")
192             .field("aiocb", &self.aiocb.0)
193             .field("in_progress", &self.in_progress)
194             .finish()
195     }
196 }
197 
198 impl Drop for AioCb {
199     /// If the `AioCb` has no remaining state in the kernel, just drop it.
200     /// Otherwise, dropping constitutes a resource leak, which is an error
drop(&mut self)201     fn drop(&mut self) {
202         assert!(
203             thread::panicking() || !self.in_progress,
204             "Dropped an in-progress AioCb"
205         );
206     }
207 }
208 
209 /// Methods common to all AIO operations
210 pub trait Aio {
211     /// The return type of [`Aio::aio_return`].
212     type Output;
213 
214     /// Retrieve return status of an asynchronous operation.
215     ///
216     /// Should only be called once for each operation, after [`Aio::error`]
217     /// indicates that it has completed.  The result is the same as for the
218     /// synchronous `read(2)`, `write(2)`, of `fsync(2)` functions.
219     ///
220     /// # References
221     ///
222     /// [aio_return](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_return.html)
aio_return(self: Pin<&mut Self>) -> Result<Self::Output>223     fn aio_return(self: Pin<&mut Self>) -> Result<Self::Output>;
224 
225     /// Cancels an outstanding AIO request.
226     ///
227     /// The operating system is not required to implement cancellation for all
228     /// file and device types.  Even if it does, there is no guarantee that the
229     /// operation has not already completed.  So the caller must check the
230     /// result and handle operations that were not canceled or that have already
231     /// completed.
232     ///
233     /// # Examples
234     ///
235     /// Cancel an outstanding aio operation.  Note that we must still call
236     /// `aio_return` to free resources, even though we don't care about the
237     /// result.
238     ///
239     /// ```
240     /// # use nix::errno::Errno;
241     /// # use nix::Error;
242     /// # use nix::sys::aio::*;
243     /// # use nix::sys::signal::SigevNotify;
244     /// # use std::{thread, time};
245     /// # use std::io::Write;
246     /// # use std::os::unix::io::AsRawFd;
247     /// # use tempfile::tempfile;
248     /// let wbuf = b"CDEF";
249     /// let mut f = tempfile().unwrap();
250     /// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(),
251     ///     2,   //offset
252     ///     &wbuf[..],
253     ///     0,   //priority
254     ///     SigevNotify::SigevNone));
255     /// aiocb.as_mut().submit().unwrap();
256     /// let cs = aiocb.as_mut().cancel().unwrap();
257     /// if cs == AioCancelStat::AioNotCanceled {
258     ///     while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) {
259     ///         thread::sleep(time::Duration::from_millis(10));
260     ///     }
261     /// }
262     /// // Must call `aio_return`, but ignore the result
263     /// let _ = aiocb.as_mut().aio_return();
264     /// ```
265     ///
266     /// # References
267     ///
268     /// [aio_cancel](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html)
cancel(self: Pin<&mut Self>) -> Result<AioCancelStat>269     fn cancel(self: Pin<&mut Self>) -> Result<AioCancelStat>;
270 
271     /// Retrieve error status of an asynchronous operation.
272     ///
273     /// If the request has not yet completed, returns `EINPROGRESS`.  Otherwise,
274     /// returns `Ok` or any other error.
275     ///
276     /// # Examples
277     ///
278     /// Issue an aio operation and use `error` to poll for completion.  Polling
279     /// is an alternative to `aio_suspend`, used by most of the other examples.
280     ///
281     /// ```
282     /// # use nix::errno::Errno;
283     /// # use nix::Error;
284     /// # use nix::sys::aio::*;
285     /// # use nix::sys::signal::SigevNotify;
286     /// # use std::{thread, time};
287     /// # use std::os::unix::io::AsRawFd;
288     /// # use tempfile::tempfile;
289     /// const WBUF: &[u8] = b"abcdef123456";
290     /// let mut f = tempfile().unwrap();
291     /// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(),
292     ///     2,   //offset
293     ///     WBUF,
294     ///     0,   //priority
295     ///     SigevNotify::SigevNone));
296     /// aiocb.as_mut().submit().unwrap();
297     /// while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) {
298     ///     thread::sleep(time::Duration::from_millis(10));
299     /// }
300     /// assert_eq!(aiocb.as_mut().aio_return().unwrap(), WBUF.len());
301     /// ```
302     ///
303     /// # References
304     ///
305     /// [aio_error](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_error.html)
error(self: Pin<&mut Self>) -> Result<()>306     fn error(self: Pin<&mut Self>) -> Result<()>;
307 
308     /// Returns the underlying file descriptor associated with the operation.
fd(&self) -> RawFd309     fn fd(&self) -> RawFd;
310 
311     /// Does this operation currently have any in-kernel state?
312     ///
313     /// Dropping an operation that does have in-kernel state constitutes a
314     /// resource leak.
315     ///
316     /// # Examples
317     ///
318     /// ```
319     /// # use nix::errno::Errno;
320     /// # use nix::Error;
321     /// # use nix::sys::aio::*;
322     /// # use nix::sys::signal::SigevNotify::SigevNone;
323     /// # use std::{thread, time};
324     /// # use std::os::unix::io::AsRawFd;
325     /// # use tempfile::tempfile;
326     /// let f = tempfile().unwrap();
327     /// let mut aiof = Box::pin(AioFsync::new(f.as_raw_fd(), AioFsyncMode::O_SYNC,
328     ///     0, SigevNone));
329     /// assert!(!aiof.as_mut().in_progress());
330     /// aiof.as_mut().submit().expect("aio_fsync failed early");
331     /// assert!(aiof.as_mut().in_progress());
332     /// while (aiof.as_mut().error() == Err(Errno::EINPROGRESS)) {
333     ///     thread::sleep(time::Duration::from_millis(10));
334     /// }
335     /// aiof.as_mut().aio_return().expect("aio_fsync failed late");
336     /// assert!(!aiof.as_mut().in_progress());
337     /// ```
in_progress(&self) -> bool338     fn in_progress(&self) -> bool;
339 
340     /// Returns the priority of the `AioCb`
priority(&self) -> i32341     fn priority(&self) -> i32;
342 
343     /// Update the notification settings for an existing AIO operation that has
344     /// not yet been submitted.
set_sigev_notify(&mut self, sev: SigevNotify)345     fn set_sigev_notify(&mut self, sev: SigevNotify);
346 
347     /// Returns the `SigEvent` that will be used for notification.
sigevent(&self) -> SigEvent348     fn sigevent(&self) -> SigEvent;
349 
350     /// Actually start the I/O operation.
351     ///
352     /// After calling this method and until [`Aio::aio_return`] returns `Ok`,
353     /// the structure may not be moved in memory.
submit(self: Pin<&mut Self>) -> Result<()>354     fn submit(self: Pin<&mut Self>) -> Result<()>;
355 }
356 
357 macro_rules! aio_methods {
358     () => {
359         fn cancel(self: Pin<&mut Self>) -> Result<AioCancelStat> {
360             self.aiocb().cancel()
361         }
362 
363         fn error(self: Pin<&mut Self>) -> Result<()> {
364             self.aiocb().error()
365         }
366 
367         fn fd(&self) -> RawFd {
368             self.aiocb.aiocb.0.aio_fildes
369         }
370 
371         fn in_progress(&self) -> bool {
372             self.aiocb.in_progress()
373         }
374 
375         fn priority(&self) -> i32 {
376             self.aiocb.aiocb.0.aio_reqprio
377         }
378 
379         fn set_sigev_notify(&mut self, sev: SigevNotify) {
380             self.aiocb.set_sigev_notify(sev)
381         }
382 
383         fn sigevent(&self) -> SigEvent {
384             SigEvent::from(&self.aiocb.aiocb.0.aio_sigevent)
385         }
386     };
387     ($func:ident) => {
388         aio_methods!();
389 
390         fn aio_return(self: Pin<&mut Self>) -> Result<<Self as Aio>::Output> {
391             self.aiocb().aio_return()
392         }
393 
394         fn submit(mut self: Pin<&mut Self>) -> Result<()> {
395             let p: *mut libc::aiocb = &mut self.as_mut().aiocb().aiocb.0;
396             Errno::result({ unsafe { libc::$func(p) } }).map(|_| {
397                 self.aiocb().set_in_progress();
398             })
399         }
400     };
401 }
402 
403 /// An asynchronous version of `fsync(2)`.
404 ///
405 /// # References
406 ///
407 /// [aio_fsync](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_fsync.html)
408 /// # Examples
409 ///
410 /// ```
411 /// # use nix::errno::Errno;
412 /// # use nix::Error;
413 /// # use nix::sys::aio::*;
414 /// # use nix::sys::signal::SigevNotify::SigevNone;
415 /// # use std::{thread, time};
416 /// # use std::os::unix::io::AsRawFd;
417 /// # use tempfile::tempfile;
418 /// let f = tempfile().unwrap();
419 /// let mut aiof = Box::pin(AioFsync::new(f.as_raw_fd(), AioFsyncMode::O_SYNC,
420 ///     0, SigevNone));
421 /// aiof.as_mut().submit().expect("aio_fsync failed early");
422 /// while (aiof.as_mut().error() == Err(Errno::EINPROGRESS)) {
423 ///     thread::sleep(time::Duration::from_millis(10));
424 /// }
425 /// aiof.as_mut().aio_return().expect("aio_fsync failed late");
426 /// ```
427 #[derive(Debug)]
428 #[repr(transparent)]
429 pub struct AioFsync {
430     aiocb: AioCb,
431     _pin: PhantomPinned,
432 }
433 
434 impl AioFsync {
435     unsafe_pinned!(aiocb: AioCb);
436 
437     /// Returns the operation's fsync mode: data and metadata or data only?
mode(&self) -> AioFsyncMode438     pub fn mode(&self) -> AioFsyncMode {
439         AioFsyncMode::try_from(self.aiocb.aiocb.0.aio_lio_opcode).unwrap()
440     }
441 
442     /// Create a new `AioFsync`.
443     ///
444     /// # Arguments
445     ///
446     /// * `fd`:           File descriptor to sync.
447     /// * `mode`:         Whether to sync file metadata too, or just data.
448     /// * `prio`:         If POSIX Prioritized IO is supported, then the
449     ///                   operation will be prioritized at the process's
450     ///                   priority level minus `prio`.
451     /// * `sigev_notify`: Determines how you will be notified of event
452     ///                   completion.
new( fd: RawFd, mode: AioFsyncMode, prio: i32, sigev_notify: SigevNotify, ) -> Self453     pub fn new(
454         fd: RawFd,
455         mode: AioFsyncMode,
456         prio: i32,
457         sigev_notify: SigevNotify,
458     ) -> Self {
459         let mut aiocb = AioCb::common_init(fd, prio, sigev_notify);
460         // To save some memory, store mode in an unused field of the AioCb.
461         // True it isn't very much memory, but downstream creates will likely
462         // create an enum containing this and other AioCb variants and pack
463         // those enums into data structures like Vec, so it adds up.
464         aiocb.aiocb.0.aio_lio_opcode = mode as libc::c_int;
465         AioFsync {
466             aiocb,
467             _pin: PhantomPinned,
468         }
469     }
470 }
471 
472 impl Aio for AioFsync {
473     type Output = ();
474 
475     aio_methods!();
476 
aio_return(self: Pin<&mut Self>) -> Result<()>477     fn aio_return(self: Pin<&mut Self>) -> Result<()> {
478         self.aiocb().aio_return().map(drop)
479     }
480 
submit(mut self: Pin<&mut Self>) -> Result<()>481     fn submit(mut self: Pin<&mut Self>) -> Result<()> {
482         let aiocb = &mut self.as_mut().aiocb().aiocb.0;
483         let mode = mem::replace(&mut aiocb.aio_lio_opcode, 0);
484         let p: *mut libc::aiocb = aiocb;
485         Errno::result(unsafe { libc::aio_fsync(mode, p) }).map(|_| {
486             self.aiocb().set_in_progress();
487         })
488     }
489 }
490 
491 // AioFsync does not need AsMut, since it can't be used with lio_listio
492 
493 impl AsRef<libc::aiocb> for AioFsync {
as_ref(&self) -> &libc::aiocb494     fn as_ref(&self) -> &libc::aiocb {
495         &self.aiocb.aiocb.0
496     }
497 }
498 
499 /// Asynchronously reads from a file descriptor into a buffer
500 ///
501 /// # References
502 ///
503 /// [aio_read](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_read.html)
504 ///
505 /// # Examples
506 ///
507 ///
508 /// ```
509 /// # use nix::errno::Errno;
510 /// # use nix::Error;
511 /// # use nix::sys::aio::*;
512 /// # use nix::sys::signal::SigevNotify;
513 /// # use std::{thread, time};
514 /// # use std::io::Write;
515 /// # use std::os::unix::io::AsRawFd;
516 /// # use tempfile::tempfile;
517 /// const INITIAL: &[u8] = b"abcdef123456";
518 /// const LEN: usize = 4;
519 /// let mut rbuf = vec![0; LEN];
520 /// let mut f = tempfile().unwrap();
521 /// f.write_all(INITIAL).unwrap();
522 /// {
523 ///     let mut aior = Box::pin(
524 ///         AioRead::new(
525 ///             f.as_raw_fd(),
526 ///             2,   //offset
527 ///             &mut rbuf,
528 ///             0,   //priority
529 ///             SigevNotify::SigevNone
530 ///         )
531 ///     );
532 ///     aior.as_mut().submit().unwrap();
533 ///     while (aior.as_mut().error() == Err(Errno::EINPROGRESS)) {
534 ///         thread::sleep(time::Duration::from_millis(10));
535 ///     }
536 ///     assert_eq!(aior.as_mut().aio_return().unwrap(), LEN);
537 /// }
538 /// assert_eq!(rbuf, b"cdef");
539 /// ```
540 #[derive(Debug)]
541 #[repr(transparent)]
542 pub struct AioRead<'a> {
543     aiocb: AioCb,
544     _data: PhantomData<&'a [u8]>,
545     _pin: PhantomPinned,
546 }
547 
548 impl<'a> AioRead<'a> {
549     unsafe_pinned!(aiocb: AioCb);
550 
551     /// Returns the requested length of the aio operation in bytes
552     ///
553     /// This method returns the *requested* length of the operation.  To get the
554     /// number of bytes actually read or written by a completed operation, use
555     /// `aio_return` instead.
nbytes(&self) -> usize556     pub fn nbytes(&self) -> usize {
557         self.aiocb.aiocb.0.aio_nbytes
558     }
559 
560     /// Create a new `AioRead`, placing the data in a mutable slice.
561     ///
562     /// # Arguments
563     ///
564     /// * `fd`:           File descriptor to read from
565     /// * `offs`:         File offset
566     /// * `buf`:          A memory buffer.  It must outlive the `AioRead`.
567     /// * `prio`:         If POSIX Prioritized IO is supported, then the
568     ///                   operation will be prioritized at the process's
569     ///                   priority level minus `prio`
570     /// * `sigev_notify`: Determines how you will be notified of event
571     ///                   completion.
new( fd: RawFd, offs: off_t, buf: &'a mut [u8], prio: i32, sigev_notify: SigevNotify, ) -> Self572     pub fn new(
573         fd: RawFd,
574         offs: off_t,
575         buf: &'a mut [u8],
576         prio: i32,
577         sigev_notify: SigevNotify,
578     ) -> Self {
579         let mut aiocb = AioCb::common_init(fd, prio, sigev_notify);
580         aiocb.aiocb.0.aio_nbytes = buf.len();
581         aiocb.aiocb.0.aio_buf = buf.as_mut_ptr().cast();
582         aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READ;
583         aiocb.aiocb.0.aio_offset = offs;
584         AioRead {
585             aiocb,
586             _data: PhantomData,
587             _pin: PhantomPinned,
588         }
589     }
590 
591     /// Returns the file offset of the operation.
offset(&self) -> off_t592     pub fn offset(&self) -> off_t {
593         self.aiocb.aiocb.0.aio_offset
594     }
595 }
596 
597 impl<'a> Aio for AioRead<'a> {
598     type Output = usize;
599 
600     aio_methods!(aio_read);
601 }
602 
603 impl<'a> AsMut<libc::aiocb> for AioRead<'a> {
as_mut(&mut self) -> &mut libc::aiocb604     fn as_mut(&mut self) -> &mut libc::aiocb {
605         &mut self.aiocb.aiocb.0
606     }
607 }
608 
609 impl<'a> AsRef<libc::aiocb> for AioRead<'a> {
as_ref(&self) -> &libc::aiocb610     fn as_ref(&self) -> &libc::aiocb {
611         &self.aiocb.aiocb.0
612     }
613 }
614 
615 /// Asynchronously reads from a file descriptor into a scatter/gather list of buffers.
616 ///
617 /// # References
618 ///
619 /// [aio_readv](https://www.freebsd.org/cgi/man.cgi?query=aio_readv)
620 ///
621 /// # Examples
622 ///
623 ///
624 #[cfg_attr(fbsd14, doc = " ```")]
625 #[cfg_attr(not(fbsd14), doc = " ```no_run")]
626 /// # use nix::errno::Errno;
627 /// # use nix::Error;
628 /// # use nix::sys::aio::*;
629 /// # use nix::sys::signal::SigevNotify;
630 /// # use std::{thread, time};
631 /// # use std::io::{IoSliceMut, Write};
632 /// # use std::os::unix::io::AsRawFd;
633 /// # use tempfile::tempfile;
634 /// const INITIAL: &[u8] = b"abcdef123456";
635 /// let mut rbuf0 = vec![0; 4];
636 /// let mut rbuf1 = vec![0; 2];
637 /// let expected_len = rbuf0.len() + rbuf1.len();
638 /// let mut rbufs = [IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)];
639 /// let mut f = tempfile().unwrap();
640 /// f.write_all(INITIAL).unwrap();
641 /// {
642 ///     let mut aior = Box::pin(
643 ///         AioReadv::new(
644 ///             f.as_raw_fd(),
645 ///             2,   //offset
646 ///             &mut rbufs,
647 ///             0,   //priority
648 ///             SigevNotify::SigevNone
649 ///         )
650 ///     );
651 ///     aior.as_mut().submit().unwrap();
652 ///     while (aior.as_mut().error() == Err(Errno::EINPROGRESS)) {
653 ///         thread::sleep(time::Duration::from_millis(10));
654 ///     }
655 ///     assert_eq!(aior.as_mut().aio_return().unwrap(), expected_len);
656 /// }
657 /// assert_eq!(rbuf0, b"cdef");
658 /// assert_eq!(rbuf1, b"12");
659 /// ```
660 #[cfg(target_os = "freebsd")]
661 #[derive(Debug)]
662 #[repr(transparent)]
663 pub struct AioReadv<'a> {
664     aiocb: AioCb,
665     _data: PhantomData<&'a [&'a [u8]]>,
666     _pin: PhantomPinned,
667 }
668 
669 #[cfg(target_os = "freebsd")]
670 impl<'a> AioReadv<'a> {
671     unsafe_pinned!(aiocb: AioCb);
672 
673     /// Returns the number of buffers the operation will read into.
iovlen(&self) -> usize674     pub fn iovlen(&self) -> usize {
675         self.aiocb.aiocb.0.aio_nbytes
676     }
677 
678     /// Create a new `AioReadv`, placing the data in a list of mutable slices.
679     ///
680     /// # Arguments
681     ///
682     /// * `fd`:           File descriptor to read from
683     /// * `offs`:         File offset
684     /// * `bufs`:         A scatter/gather list of memory buffers.  They must
685     ///                   outlive the `AioReadv`.
686     /// * `prio`:         If POSIX Prioritized IO is supported, then the
687     ///                   operation will be prioritized at the process's
688     ///                   priority level minus `prio`
689     /// * `sigev_notify`: Determines how you will be notified of event
690     ///                   completion.
new( fd: RawFd, offs: off_t, bufs: &mut [IoSliceMut<'a>], prio: i32, sigev_notify: SigevNotify, ) -> Self691     pub fn new(
692         fd: RawFd,
693         offs: off_t,
694         bufs: &mut [IoSliceMut<'a>],
695         prio: i32,
696         sigev_notify: SigevNotify,
697     ) -> Self {
698         let mut aiocb = AioCb::common_init(fd, prio, sigev_notify);
699         // In vectored mode, aio_nbytes stores the length of the iovec array,
700         // not the byte count.
701         aiocb.aiocb.0.aio_nbytes = bufs.len();
702         aiocb.aiocb.0.aio_buf = bufs.as_mut_ptr().cast();
703         aiocb.aiocb.0.aio_lio_opcode = libc::LIO_READV;
704         aiocb.aiocb.0.aio_offset = offs;
705         AioReadv {
706             aiocb,
707             _data: PhantomData,
708             _pin: PhantomPinned,
709         }
710     }
711 
712     /// Returns the file offset of the operation.
offset(&self) -> off_t713     pub fn offset(&self) -> off_t {
714         self.aiocb.aiocb.0.aio_offset
715     }
716 }
717 
718 #[cfg(target_os = "freebsd")]
719 impl<'a> Aio for AioReadv<'a> {
720     type Output = usize;
721 
722     aio_methods!(aio_readv);
723 }
724 
725 #[cfg(target_os = "freebsd")]
726 impl<'a> AsMut<libc::aiocb> for AioReadv<'a> {
as_mut(&mut self) -> &mut libc::aiocb727     fn as_mut(&mut self) -> &mut libc::aiocb {
728         &mut self.aiocb.aiocb.0
729     }
730 }
731 
732 #[cfg(target_os = "freebsd")]
733 impl<'a> AsRef<libc::aiocb> for AioReadv<'a> {
as_ref(&self) -> &libc::aiocb734     fn as_ref(&self) -> &libc::aiocb {
735         &self.aiocb.aiocb.0
736     }
737 }
738 
739 /// Asynchronously writes from a buffer to a file descriptor
740 ///
741 /// # References
742 ///
743 /// [aio_write](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_write.html)
744 ///
745 /// # Examples
746 ///
747 /// ```
748 /// # use nix::errno::Errno;
749 /// # use nix::Error;
750 /// # use nix::sys::aio::*;
751 /// # use nix::sys::signal::SigevNotify;
752 /// # use std::{thread, time};
753 /// # use std::os::unix::io::AsRawFd;
754 /// # use tempfile::tempfile;
755 /// const WBUF: &[u8] = b"abcdef123456";
756 /// let mut f = tempfile().unwrap();
757 /// let mut aiow = Box::pin(
758 ///     AioWrite::new(
759 ///         f.as_raw_fd(),
760 ///         2,   //offset
761 ///         WBUF,
762 ///         0,   //priority
763 ///         SigevNotify::SigevNone
764 ///     )
765 /// );
766 /// aiow.as_mut().submit().unwrap();
767 /// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) {
768 ///     thread::sleep(time::Duration::from_millis(10));
769 /// }
770 /// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len());
771 /// ```
772 #[derive(Debug)]
773 #[repr(transparent)]
774 pub struct AioWrite<'a> {
775     aiocb: AioCb,
776     _data: PhantomData<&'a [u8]>,
777     _pin: PhantomPinned,
778 }
779 
780 impl<'a> AioWrite<'a> {
781     unsafe_pinned!(aiocb: AioCb);
782 
783     /// Returns the requested length of the aio operation in bytes
784     ///
785     /// This method returns the *requested* length of the operation.  To get the
786     /// number of bytes actually read or written by a completed operation, use
787     /// `aio_return` instead.
nbytes(&self) -> usize788     pub fn nbytes(&self) -> usize {
789         self.aiocb.aiocb.0.aio_nbytes
790     }
791 
792     /// Construct a new `AioWrite`.
793     ///
794     /// # Arguments
795     ///
796     /// * `fd`:           File descriptor to write to
797     /// * `offs`:         File offset
798     /// * `buf`:          A memory buffer.  It must outlive the `AioWrite`.
799     /// * `prio`:         If POSIX Prioritized IO is supported, then the
800     ///                   operation will be prioritized at the process's
801     ///                   priority level minus `prio`
802     /// * `sigev_notify`: Determines how you will be notified of event
803     ///                   completion.
new( fd: RawFd, offs: off_t, buf: &'a [u8], prio: i32, sigev_notify: SigevNotify, ) -> Self804     pub fn new(
805         fd: RawFd,
806         offs: off_t,
807         buf: &'a [u8],
808         prio: i32,
809         sigev_notify: SigevNotify,
810     ) -> Self {
811         let mut aiocb = AioCb::common_init(fd, prio, sigev_notify);
812         aiocb.aiocb.0.aio_nbytes = buf.len();
813         // casting an immutable buffer to a mutable pointer looks unsafe,
814         // but technically its only unsafe to dereference it, not to create
815         // it.  Type Safety guarantees that we'll never pass aiocb to
816         // aio_read or aio_readv.
817         aiocb.aiocb.0.aio_buf = buf.as_ptr().cast_mut().cast();
818         aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITE;
819         aiocb.aiocb.0.aio_offset = offs;
820         AioWrite {
821             aiocb,
822             _data: PhantomData,
823             _pin: PhantomPinned,
824         }
825     }
826 
827     /// Returns the file offset of the operation.
offset(&self) -> off_t828     pub fn offset(&self) -> off_t {
829         self.aiocb.aiocb.0.aio_offset
830     }
831 }
832 
833 impl<'a> Aio for AioWrite<'a> {
834     type Output = usize;
835 
836     aio_methods!(aio_write);
837 }
838 
839 impl<'a> AsMut<libc::aiocb> for AioWrite<'a> {
as_mut(&mut self) -> &mut libc::aiocb840     fn as_mut(&mut self) -> &mut libc::aiocb {
841         &mut self.aiocb.aiocb.0
842     }
843 }
844 
845 impl<'a> AsRef<libc::aiocb> for AioWrite<'a> {
as_ref(&self) -> &libc::aiocb846     fn as_ref(&self) -> &libc::aiocb {
847         &self.aiocb.aiocb.0
848     }
849 }
850 
851 /// Asynchronously writes from a scatter/gather list of buffers to a file descriptor.
852 ///
853 /// # References
854 ///
855 /// [aio_writev](https://www.freebsd.org/cgi/man.cgi?query=aio_writev)
856 ///
857 /// # Examples
858 ///
859 #[cfg_attr(fbsd14, doc = " ```")]
860 #[cfg_attr(not(fbsd14), doc = " ```no_run")]
861 /// # use nix::errno::Errno;
862 /// # use nix::Error;
863 /// # use nix::sys::aio::*;
864 /// # use nix::sys::signal::SigevNotify;
865 /// # use std::{thread, time};
866 /// # use std::io::IoSlice;
867 /// # use std::os::unix::io::AsRawFd;
868 /// # use tempfile::tempfile;
869 /// const wbuf0: &[u8] = b"abcdef";
870 /// const wbuf1: &[u8] = b"123456";
871 /// let len = wbuf0.len() + wbuf1.len();
872 /// let wbufs = [IoSlice::new(wbuf0), IoSlice::new(wbuf1)];
873 /// let mut f = tempfile().unwrap();
874 /// let mut aiow = Box::pin(
875 ///     AioWritev::new(
876 ///         f.as_raw_fd(),
877 ///         2,   //offset
878 ///         &wbufs,
879 ///         0,   //priority
880 ///         SigevNotify::SigevNone
881 ///     )
882 /// );
883 /// aiow.as_mut().submit().unwrap();
884 /// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) {
885 ///     thread::sleep(time::Duration::from_millis(10));
886 /// }
887 /// assert_eq!(aiow.as_mut().aio_return().unwrap(), len);
888 /// ```
889 #[cfg(target_os = "freebsd")]
890 #[derive(Debug)]
891 #[repr(transparent)]
892 pub struct AioWritev<'a> {
893     aiocb: AioCb,
894     _data: PhantomData<&'a [&'a [u8]]>,
895     _pin: PhantomPinned,
896 }
897 
898 #[cfg(target_os = "freebsd")]
899 impl<'a> AioWritev<'a> {
900     unsafe_pinned!(aiocb: AioCb);
901 
902     /// Returns the number of buffers the operation will read into.
iovlen(&self) -> usize903     pub fn iovlen(&self) -> usize {
904         self.aiocb.aiocb.0.aio_nbytes
905     }
906 
907     /// Construct a new `AioWritev`.
908     ///
909     /// # Arguments
910     ///
911     /// * `fd`:           File descriptor to write to
912     /// * `offs`:         File offset
913     /// * `bufs`:         A scatter/gather list of memory buffers.  They must
914     ///                   outlive the `AioWritev`.
915     /// * `prio`:         If POSIX Prioritized IO is supported, then the
916     ///                   operation will be prioritized at the process's
917     ///                   priority level minus `prio`
918     /// * `sigev_notify`: Determines how you will be notified of event
919     ///                   completion.
new( fd: RawFd, offs: off_t, bufs: &[IoSlice<'a>], prio: i32, sigev_notify: SigevNotify, ) -> Self920     pub fn new(
921         fd: RawFd,
922         offs: off_t,
923         bufs: &[IoSlice<'a>],
924         prio: i32,
925         sigev_notify: SigevNotify,
926     ) -> Self {
927         let mut aiocb = AioCb::common_init(fd, prio, sigev_notify);
928         // In vectored mode, aio_nbytes stores the length of the iovec array,
929         // not the byte count.
930         aiocb.aiocb.0.aio_nbytes = bufs.len();
931         // casting an immutable buffer to a mutable pointer looks unsafe,
932         // but technically its only unsafe to dereference it, not to create
933         // it.  Type Safety guarantees that we'll never pass aiocb to
934         // aio_read or aio_readv.
935         aiocb.aiocb.0.aio_buf = bufs.as_ptr().cast_mut().cast();
936         aiocb.aiocb.0.aio_lio_opcode = libc::LIO_WRITEV;
937         aiocb.aiocb.0.aio_offset = offs;
938         AioWritev {
939             aiocb,
940             _data: PhantomData,
941             _pin: PhantomPinned,
942         }
943     }
944 
945     /// Returns the file offset of the operation.
offset(&self) -> off_t946     pub fn offset(&self) -> off_t {
947         self.aiocb.aiocb.0.aio_offset
948     }
949 }
950 
951 #[cfg(target_os = "freebsd")]
952 impl<'a> Aio for AioWritev<'a> {
953     type Output = usize;
954 
955     aio_methods!(aio_writev);
956 }
957 
958 #[cfg(target_os = "freebsd")]
959 impl<'a> AsMut<libc::aiocb> for AioWritev<'a> {
as_mut(&mut self) -> &mut libc::aiocb960     fn as_mut(&mut self) -> &mut libc::aiocb {
961         &mut self.aiocb.aiocb.0
962     }
963 }
964 
965 #[cfg(target_os = "freebsd")]
966 impl<'a> AsRef<libc::aiocb> for AioWritev<'a> {
as_ref(&self) -> &libc::aiocb967     fn as_ref(&self) -> &libc::aiocb {
968         &self.aiocb.aiocb.0
969     }
970 }
971 
972 /// Cancels outstanding AIO requests for a given file descriptor.
973 ///
974 /// # Examples
975 ///
976 /// Issue an aio operation, then cancel all outstanding operations on that file
977 /// descriptor.
978 ///
979 /// ```
980 /// # use nix::errno::Errno;
981 /// # use nix::Error;
982 /// # use nix::sys::aio::*;
983 /// # use nix::sys::signal::SigevNotify;
984 /// # use std::{thread, time};
985 /// # use std::io::Write;
986 /// # use std::os::unix::io::AsRawFd;
987 /// # use tempfile::tempfile;
988 /// let wbuf = b"CDEF";
989 /// let mut f = tempfile().unwrap();
990 /// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(),
991 ///     2,   //offset
992 ///     &wbuf[..],
993 ///     0,   //priority
994 ///     SigevNotify::SigevNone));
995 /// aiocb.as_mut().submit().unwrap();
996 /// let cs = aio_cancel_all(f.as_raw_fd()).unwrap();
997 /// if cs == AioCancelStat::AioNotCanceled {
998 ///     while (aiocb.as_mut().error() == Err(Errno::EINPROGRESS)) {
999 ///         thread::sleep(time::Duration::from_millis(10));
1000 ///     }
1001 /// }
1002 /// // Must call `aio_return`, but ignore the result
1003 /// let _ = aiocb.as_mut().aio_return();
1004 /// ```
1005 ///
1006 /// # References
1007 ///
1008 /// [`aio_cancel`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html)
aio_cancel_all(fd: RawFd) -> Result<AioCancelStat>1009 pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> {
1010     match unsafe { libc::aio_cancel(fd, ptr::null_mut()) } {
1011         libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled),
1012         libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled),
1013         libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone),
1014         -1 => Err(Errno::last()),
1015         _ => panic!("unknown aio_cancel return value"),
1016     }
1017 }
1018 
1019 /// Suspends the calling process until at least one of the specified operations
1020 /// have completed, a signal is delivered, or the timeout has passed.
1021 ///
1022 /// If `timeout` is `None`, `aio_suspend` will block indefinitely.
1023 ///
1024 /// # Examples
1025 ///
1026 /// Use `aio_suspend` to block until an aio operation completes.
1027 ///
1028 /// ```
1029 /// # use nix::sys::aio::*;
1030 /// # use nix::sys::signal::SigevNotify;
1031 /// # use std::os::unix::io::AsRawFd;
1032 /// # use tempfile::tempfile;
1033 /// const WBUF: &[u8] = b"abcdef123456";
1034 /// let mut f = tempfile().unwrap();
1035 /// let mut aiocb = Box::pin(AioWrite::new(f.as_raw_fd(),
1036 ///     2,   //offset
1037 ///     WBUF,
1038 ///     0,   //priority
1039 ///     SigevNotify::SigevNone));
1040 /// aiocb.as_mut().submit().unwrap();
1041 /// aio_suspend(&[&*aiocb], None).expect("aio_suspend failed");
1042 /// assert_eq!(aiocb.as_mut().aio_return().unwrap() as usize, WBUF.len());
1043 /// ```
1044 /// # References
1045 ///
1046 /// [`aio_suspend`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_suspend.html)
aio_suspend( list: &[&dyn AsRef<libc::aiocb>], timeout: Option<TimeSpec>, ) -> Result<()>1047 pub fn aio_suspend(
1048     list: &[&dyn AsRef<libc::aiocb>],
1049     timeout: Option<TimeSpec>,
1050 ) -> Result<()> {
1051     // Note that this allocation could be eliminated by making the argument
1052     // generic, and accepting arguments like &[AioWrite].  But that would
1053     // prevent using aio_suspend to wait on a heterogeneous list of mixed
1054     // operations.
1055     let v = list
1056         .iter()
1057         .map(|x| x.as_ref() as *const libc::aiocb)
1058         .collect::<Vec<*const libc::aiocb>>();
1059     let p = v.as_ptr();
1060     let timep = match timeout {
1061         None => ptr::null::<libc::timespec>(),
1062         Some(x) => x.as_ref() as *const libc::timespec,
1063     };
1064     Errno::result(unsafe { libc::aio_suspend(p, list.len() as i32, timep) })
1065         .map(drop)
1066 }
1067 
1068 /// Submits multiple asynchronous I/O requests with a single system call.
1069 ///
1070 /// They are not guaranteed to complete atomically, and the order in which the
1071 /// requests are carried out is not specified. Reads, and writes may be freely
1072 /// mixed.
1073 ///
1074 /// # Examples
1075 ///
1076 /// Use `lio_listio` to submit an aio operation and wait for its completion. In
1077 /// this case, there is no need to use aio_suspend to wait or `error` to poll.
1078 /// This mode is useful for otherwise-synchronous programs that want to execute
1079 /// a handful of I/O operations in parallel.
1080 /// ```
1081 /// # use std::os::unix::io::AsRawFd;
1082 /// # use nix::sys::aio::*;
1083 /// # use nix::sys::signal::SigevNotify;
1084 /// # use tempfile::tempfile;
1085 /// const WBUF: &[u8] = b"abcdef123456";
1086 /// let mut f = tempfile().unwrap();
1087 /// let mut aiow = Box::pin(AioWrite::new(
1088 ///     f.as_raw_fd(),
1089 ///     2,      // offset
1090 ///     WBUF,
1091 ///     0,      // priority
1092 ///     SigevNotify::SigevNone
1093 /// ));
1094 /// lio_listio(LioMode::LIO_WAIT, &mut[aiow.as_mut()], SigevNotify::SigevNone)
1095 ///     .unwrap();
1096 /// // At this point, we are guaranteed that aiow is complete.
1097 /// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len());
1098 /// ```
1099 ///
1100 /// Use `lio_listio` to submit multiple asynchronous operations with a single
1101 /// syscall, but receive notification individually.  This is an efficient
1102 /// technique for reducing overall context-switch overhead, especially when
1103 /// combined with kqueue.
1104 /// ```
1105 /// # use std::os::unix::io::AsRawFd;
1106 /// # use std::thread;
1107 /// # use std::time;
1108 /// # use nix::errno::Errno;
1109 /// # use nix::sys::aio::*;
1110 /// # use nix::sys::signal::SigevNotify;
1111 /// # use tempfile::tempfile;
1112 /// const WBUF: &[u8] = b"abcdef123456";
1113 /// let mut f = tempfile().unwrap();
1114 /// let mut aiow = Box::pin(AioWrite::new(
1115 ///     f.as_raw_fd(),
1116 ///     2,      // offset
1117 ///     WBUF,
1118 ///     0,      // priority
1119 ///     SigevNotify::SigevNone
1120 /// ));
1121 /// lio_listio(LioMode::LIO_NOWAIT, &mut[aiow.as_mut()], SigevNotify::SigevNone)
1122 ///     .unwrap();
1123 /// // We must wait for the completion of each individual operation
1124 /// while (aiow.as_mut().error() == Err(Errno::EINPROGRESS)) {
1125 ///     thread::sleep(time::Duration::from_millis(10));
1126 /// }
1127 /// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len());
1128 /// ```
1129 ///
1130 /// Use `lio_listio` to submit multiple operations, and receive notification
1131 /// only when all of them are complete.  This can be useful when there is some
1132 /// logical relationship between the operations.  But beware!  Errors or system
1133 /// resource limitations may cause `lio_listio` to return `EIO`, `EAGAIN`, or
1134 /// `EINTR`, in which case some but not all operations may have been submitted.
1135 /// In that case, you must check the status of each individual operation, and
1136 /// possibly resubmit some.
1137 /// ```
1138 /// # use libc::c_int;
1139 /// # use std::os::unix::io::AsRawFd;
1140 /// # use std::sync::atomic::{AtomicBool, Ordering};
1141 /// # use std::thread;
1142 /// # use std::time;
1143 /// # use nix::errno::Errno;
1144 /// # use nix::sys::aio::*;
1145 /// # use nix::sys::signal::*;
1146 /// # use tempfile::tempfile;
1147 /// pub static SIGNALED: AtomicBool = AtomicBool::new(false);
1148 ///
1149 /// extern fn sigfunc(_: c_int) {
1150 ///     SIGNALED.store(true, Ordering::Relaxed);
1151 /// }
1152 /// let sa = SigAction::new(SigHandler::Handler(sigfunc),
1153 ///                         SaFlags::SA_RESETHAND,
1154 ///                         SigSet::empty());
1155 /// SIGNALED.store(false, Ordering::Relaxed);
1156 /// unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap();
1157 ///
1158 /// const WBUF: &[u8] = b"abcdef123456";
1159 /// let mut f = tempfile().unwrap();
1160 /// let mut aiow = Box::pin(AioWrite::new(
1161 ///     f.as_raw_fd(),
1162 ///     2,      // offset
1163 ///     WBUF,
1164 ///     0,      // priority
1165 ///     SigevNotify::SigevNone
1166 /// ));
1167 /// let sev = SigevNotify::SigevSignal { signal: Signal::SIGUSR2, si_value: 0 };
1168 /// lio_listio(LioMode::LIO_NOWAIT, &mut[aiow.as_mut()], sev).unwrap();
1169 /// while !SIGNALED.load(Ordering::Relaxed) {
1170 ///     thread::sleep(time::Duration::from_millis(10));
1171 /// }
1172 /// // At this point, since `lio_listio` returned success and delivered its
1173 /// // notification, we know that all operations are complete.
1174 /// assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len());
1175 /// ```
1176 #[deprecated(
1177     since = "0.27.0",
1178     note = "https://github.com/nix-rust/nix/issues/2017"
1179 )]
lio_listio( mode: LioMode, list: &mut [Pin<&mut dyn AsMut<libc::aiocb>>], sigev_notify: SigevNotify, ) -> Result<()>1180 pub fn lio_listio(
1181     mode: LioMode,
1182     list: &mut [Pin<&mut dyn AsMut<libc::aiocb>>],
1183     sigev_notify: SigevNotify,
1184 ) -> Result<()> {
1185     let p = list as *mut [Pin<&mut dyn AsMut<libc::aiocb>>]
1186         as *mut [*mut libc::aiocb] as *mut *mut libc::aiocb;
1187     let sigev = SigEvent::new(sigev_notify);
1188     let sigevp = &mut sigev.sigevent() as *mut libc::sigevent;
1189     Errno::result(unsafe {
1190         libc::lio_listio(mode as i32, p, list.len() as i32, sigevp)
1191     })
1192     .map(drop)
1193 }
1194