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