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