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