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