• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::{
2     io::{Read, Seek, Write},
3     ops::Deref,
4     os::unix::io::{AsFd, AsRawFd, BorrowedFd},
5     pin::Pin,
6     sync::atomic::{AtomicBool, Ordering},
7     thread, time,
8 };
9 
10 use libc::c_int;
11 use nix::{
12     errno::*,
13     sys::{
14         aio::*,
15         signal::{
16             sigaction, SaFlags, SigAction, SigHandler, SigSet, SigevNotify,
17             Signal,
18         },
19         time::{TimeSpec, TimeValLike},
20     },
21 };
22 use tempfile::tempfile;
23 
24 pub static SIGNALED: AtomicBool = AtomicBool::new(false);
25 
sigfunc(_: c_int)26 extern "C" fn sigfunc(_: c_int) {
27     SIGNALED.store(true, Ordering::Relaxed);
28 }
29 
30 // Helper that polls an AioCb for completion or error
31 macro_rules! poll_aio {
32     ($aiocb: expr) => {
33         loop {
34             let err = $aiocb.as_mut().error();
35             if err != Err(Errno::EINPROGRESS) {
36                 break err;
37             };
38             thread::sleep(time::Duration::from_millis(10));
39         }
40     };
41 }
42 
43 mod aio_fsync {
44     use super::*;
45 
46     #[test]
test_accessors()47     fn test_accessors() {
48         let f = tempfile().unwrap();
49         let aiocb = AioFsync::new(
50             f.as_fd(),
51             AioFsyncMode::O_SYNC,
52             42,
53             SigevNotify::SigevSignal {
54                 signal: Signal::SIGUSR2,
55                 si_value: 99,
56             },
57         );
58         assert_eq!(f.as_raw_fd(), aiocb.fd().as_raw_fd());
59         assert_eq!(AioFsyncMode::O_SYNC, aiocb.mode());
60         assert_eq!(42, aiocb.priority());
61         let sev = aiocb.sigevent().sigevent();
62         assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo);
63         assert_eq!(99, sev.sigev_value.sival_ptr as i64);
64     }
65 
66     /// `AioFsync::submit` should not modify the `AioCb` object if
67     /// `libc::aio_fsync` returns an error
68     // Skip on Linux, because Linux's AIO implementation can't detect errors
69     // synchronously
70     #[test]
71     #[cfg_attr(any(target_os = "android", target_os = "linux"), ignore)]
error()72     fn error() {
73         use std::mem;
74 
75         const INITIAL: &[u8] = b"abcdef123456";
76         // Create an invalid AioFsyncMode
77         let mode = unsafe { mem::transmute::<i32, AioFsyncMode>(666) };
78         let mut f = tempfile().unwrap();
79         f.write_all(INITIAL).unwrap();
80         let mut aiof =
81             Box::pin(AioFsync::new(f.as_fd(), mode, 0, SigevNotify::SigevNone));
82         let err = aiof.as_mut().submit();
83         err.expect_err("assertion failed");
84     }
85 
86     #[test]
87     #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
ok()88     fn ok() {
89         const INITIAL: &[u8] = b"abcdef123456";
90         let mut f = tempfile().unwrap();
91         f.write_all(INITIAL).unwrap();
92         let mut aiof = Box::pin(AioFsync::new(
93             f.as_fd(),
94             AioFsyncMode::O_SYNC,
95             0,
96             SigevNotify::SigevNone,
97         ));
98         aiof.as_mut().submit().unwrap();
99         poll_aio!(&mut aiof).unwrap();
100         aiof.as_mut().aio_return().unwrap();
101     }
102 }
103 
104 mod aio_read {
105     use super::*;
106 
107     #[test]
test_accessors()108     fn test_accessors() {
109         let f = tempfile().unwrap();
110         let mut rbuf = vec![0; 4];
111         let aiocb = AioRead::new(
112             f.as_fd(),
113             2, //offset
114             &mut rbuf,
115             42, //priority
116             SigevNotify::SigevSignal {
117                 signal: Signal::SIGUSR2,
118                 si_value: 99,
119             },
120         );
121         assert_eq!(f.as_raw_fd(), aiocb.fd().as_raw_fd());
122         assert_eq!(4, aiocb.nbytes());
123         assert_eq!(2, aiocb.offset());
124         assert_eq!(42, aiocb.priority());
125         let sev = aiocb.sigevent().sigevent();
126         assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo);
127         assert_eq!(99, sev.sigev_value.sival_ptr as i64);
128     }
129 
130     // Tests AioWrite.cancel.  We aren't trying to test the OS's implementation,
131     // only our bindings.  So it's sufficient to check that cancel
132     // returned any AioCancelStat value.
133     #[test]
134     #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
cancel()135     fn cancel() {
136         const INITIAL: &[u8] = b"abcdef123456";
137         let mut rbuf = vec![0; 4];
138         let mut f = tempfile().unwrap();
139         f.write_all(INITIAL).unwrap();
140         let fd = f.as_fd();
141         let mut aior =
142             Box::pin(AioRead::new(fd, 2, &mut rbuf, 0, SigevNotify::SigevNone));
143         aior.as_mut().submit().unwrap();
144 
145         aior.as_mut().cancel().unwrap();
146 
147         // Wait for aiow to complete, but don't care whether it succeeded
148         let _ = poll_aio!(&mut aior);
149         let _ = aior.as_mut().aio_return();
150     }
151 
152     /// `AioRead::submit` should not modify the `AioCb` object if
153     /// `libc::aio_read` returns an error
154     // Skip on Linux, because Linux's AIO implementation can't detect errors
155     // synchronously
156     #[test]
157     #[cfg(any(target_os = "freebsd", apple_targets))]
error()158     fn error() {
159         const INITIAL: &[u8] = b"abcdef123456";
160         let mut rbuf = vec![0; 4];
161         let mut f = tempfile().unwrap();
162         f.write_all(INITIAL).unwrap();
163         let mut aior = Box::pin(AioRead::new(
164             f.as_fd(),
165             -1, //an invalid offset
166             &mut rbuf,
167             0, //priority
168             SigevNotify::SigevNone,
169         ));
170         aior.as_mut().submit().expect_err("assertion failed");
171     }
172 
173     // Test a simple aio operation with no completion notification.  We must
174     // poll for completion
175     #[test]
176     #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
ok()177     fn ok() {
178         const INITIAL: &[u8] = b"abcdef123456";
179         let mut rbuf = vec![0; 4];
180         const EXPECT: &[u8] = b"cdef";
181         let mut f = tempfile().unwrap();
182         f.write_all(INITIAL).unwrap();
183         {
184             let fd = f.as_fd();
185             let mut aior = Box::pin(AioRead::new(
186                 fd,
187                 2,
188                 &mut rbuf,
189                 0,
190                 SigevNotify::SigevNone,
191             ));
192             aior.as_mut().submit().unwrap();
193 
194             let err = poll_aio!(&mut aior);
195             assert_eq!(err, Ok(()));
196             assert_eq!(aior.as_mut().aio_return().unwrap(), EXPECT.len());
197         }
198         assert_eq!(EXPECT, rbuf.deref());
199     }
200 
201     // Like ok, but allocates the structure on the stack.
202     #[test]
203     #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
on_stack()204     fn on_stack() {
205         const INITIAL: &[u8] = b"abcdef123456";
206         let mut rbuf = vec![0; 4];
207         const EXPECT: &[u8] = b"cdef";
208         let mut f = tempfile().unwrap();
209         f.write_all(INITIAL).unwrap();
210         {
211             let fd = f.as_fd();
212             let mut aior =
213                 AioRead::new(fd, 2, &mut rbuf, 0, SigevNotify::SigevNone);
214             let mut aior = unsafe { Pin::new_unchecked(&mut aior) };
215             aior.as_mut().submit().unwrap();
216 
217             let err = poll_aio!(&mut aior);
218             assert_eq!(err, Ok(()));
219             assert_eq!(aior.as_mut().aio_return().unwrap(), EXPECT.len());
220         }
221         assert_eq!(EXPECT, rbuf.deref());
222     }
223 }
224 
225 #[cfg(target_os = "freebsd")]
226 #[cfg(fbsd14)]
227 mod aio_readv {
228     use std::io::IoSliceMut;
229 
230     use super::*;
231 
232     #[test]
test_accessors()233     fn test_accessors() {
234         let f = tempfile().unwrap();
235         let mut rbuf0 = vec![0; 4];
236         let mut rbuf1 = vec![0; 8];
237         let mut rbufs =
238             [IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)];
239         let aiocb = AioReadv::new(
240             f.as_fd(),
241             2, //offset
242             &mut rbufs,
243             42, //priority
244             SigevNotify::SigevSignal {
245                 signal: Signal::SIGUSR2,
246                 si_value: 99,
247             },
248         );
249         assert_eq!(f.as_raw_fd(), aiocb.fd().as_raw_fd());
250         assert_eq!(2, aiocb.iovlen());
251         assert_eq!(2, aiocb.offset());
252         assert_eq!(42, aiocb.priority());
253         let sev = aiocb.sigevent().sigevent();
254         assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo);
255         assert_eq!(99, sev.sigev_value.sival_ptr as i64);
256     }
257 
258     #[test]
259     #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
ok()260     fn ok() {
261         const INITIAL: &[u8] = b"abcdef123456";
262         let mut rbuf0 = vec![0; 4];
263         let mut rbuf1 = vec![0; 2];
264         let mut rbufs =
265             [IoSliceMut::new(&mut rbuf0), IoSliceMut::new(&mut rbuf1)];
266         const EXPECT0: &[u8] = b"cdef";
267         const EXPECT1: &[u8] = b"12";
268         let mut f = tempfile().unwrap();
269         f.write_all(INITIAL).unwrap();
270         {
271             let fd = f.as_fd();
272             let mut aior = Box::pin(AioReadv::new(
273                 fd,
274                 2,
275                 &mut rbufs,
276                 0,
277                 SigevNotify::SigevNone,
278             ));
279             aior.as_mut().submit().unwrap();
280 
281             let err = poll_aio!(&mut aior);
282             assert_eq!(err, Ok(()));
283             assert_eq!(
284                 aior.as_mut().aio_return().unwrap(),
285                 EXPECT0.len() + EXPECT1.len()
286             );
287         }
288         assert_eq!(&EXPECT0, &rbuf0);
289         assert_eq!(&EXPECT1, &rbuf1);
290     }
291 }
292 
293 mod aio_write {
294     use super::*;
295 
296     #[test]
test_accessors()297     fn test_accessors() {
298         let f = tempfile().unwrap();
299         let wbuf = vec![0; 4];
300         let aiocb = AioWrite::new(
301             f.as_fd(),
302             2, //offset
303             &wbuf,
304             42, //priority
305             SigevNotify::SigevSignal {
306                 signal: Signal::SIGUSR2,
307                 si_value: 99,
308             },
309         );
310         assert_eq!(f.as_raw_fd(), aiocb.fd().as_raw_fd());
311         assert_eq!(4, aiocb.nbytes());
312         assert_eq!(2, aiocb.offset());
313         assert_eq!(42, aiocb.priority());
314         let sev = aiocb.sigevent().sigevent();
315         assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo);
316         assert_eq!(99, sev.sigev_value.sival_ptr as i64);
317     }
318 
319     // Tests AioWrite.cancel.  We aren't trying to test the OS's implementation,
320     // only our bindings.  So it's sufficient to check that cancel
321     // returned any AioCancelStat value.
322     #[test]
323     #[cfg_attr(target_env = "musl", ignore)]
cancel()324     fn cancel() {
325         let wbuf: &[u8] = b"CDEF";
326 
327         let f = tempfile().unwrap();
328         let mut aiow = Box::pin(AioWrite::new(
329             f.as_fd(),
330             0,
331             wbuf,
332             0,
333             SigevNotify::SigevNone,
334         ));
335         aiow.as_mut().submit().unwrap();
336         let err = aiow.as_mut().error();
337         assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS));
338 
339         aiow.as_mut().cancel().unwrap();
340 
341         // Wait for aiow to complete, but don't care whether it succeeded
342         let _ = poll_aio!(&mut aiow);
343         let _ = aiow.as_mut().aio_return();
344     }
345 
346     // Test a simple aio operation with no completion notification.  We must
347     // poll for completion.
348     #[test]
349     #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
ok()350     fn ok() {
351         const INITIAL: &[u8] = b"abcdef123456";
352         let wbuf = "CDEF".to_string().into_bytes();
353         let mut rbuf = Vec::new();
354         const EXPECT: &[u8] = b"abCDEF123456";
355 
356         let mut f = tempfile().unwrap();
357         f.write_all(INITIAL).unwrap();
358         {
359             let mut aiow = Box::pin(AioWrite::new(
360                 f.as_fd(),
361                 2,
362                 &wbuf,
363                 0,
364                 SigevNotify::SigevNone,
365             ));
366             aiow.as_mut().submit().unwrap();
367 
368             let err = poll_aio!(&mut aiow);
369             assert_eq!(err, Ok(()));
370             assert_eq!(aiow.as_mut().aio_return().unwrap(), wbuf.len());
371         }
372 
373         f.rewind().unwrap();
374         let len = f.read_to_end(&mut rbuf).unwrap();
375         assert_eq!(len, EXPECT.len());
376         assert_eq!(rbuf, EXPECT);
377     }
378 
379     // Like ok, but allocates the structure on the stack.
380     #[test]
381     #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
on_stack()382     fn on_stack() {
383         const INITIAL: &[u8] = b"abcdef123456";
384         let wbuf = "CDEF".to_string().into_bytes();
385         let mut rbuf = Vec::new();
386         const EXPECT: &[u8] = b"abCDEF123456";
387 
388         let mut f = tempfile().unwrap();
389         f.write_all(INITIAL).unwrap();
390         {
391             let mut aiow = AioWrite::new(
392                 f.as_fd(),
393                 2, //offset
394                 &wbuf,
395                 0, //priority
396                 SigevNotify::SigevNone,
397             );
398             let mut aiow = unsafe { Pin::new_unchecked(&mut aiow) };
399             aiow.as_mut().submit().unwrap();
400 
401             let err = poll_aio!(&mut aiow);
402             assert_eq!(err, Ok(()));
403             assert_eq!(aiow.as_mut().aio_return().unwrap(), wbuf.len());
404         }
405 
406         f.rewind().unwrap();
407         let len = f.read_to_end(&mut rbuf).unwrap();
408         assert_eq!(len, EXPECT.len());
409         assert_eq!(rbuf, EXPECT);
410     }
411 
412     /// `AioWrite::write` should not modify the `AioCb` object if
413     /// `libc::aio_write` returns an error.
414     // Skip on Linux, because Linux's AIO implementation can't detect errors
415     // synchronously
416     #[test]
417     #[cfg_attr(any(target_os = "android", target_os = "linux"), ignore)]
error()418     fn error() {
419         // Not I/O safe!  Deliberately create an invalid fd.
420         let fd = unsafe { BorrowedFd::borrow_raw(666) };
421         let wbuf = "CDEF".to_string().into_bytes();
422         let mut aiow = Box::pin(AioWrite::new(
423             fd,
424             0, //offset
425             &wbuf,
426             0, //priority
427             SigevNotify::SigevNone,
428         ));
429         aiow.as_mut().submit().expect_err("assertion failed");
430         // Dropping the AioWrite at this point should not panic
431     }
432 }
433 
434 #[cfg(target_os = "freebsd")]
435 #[cfg(fbsd14)]
436 mod aio_writev {
437     use std::io::IoSlice;
438 
439     use super::*;
440 
441     #[test]
test_accessors()442     fn test_accessors() {
443         let f = tempfile().unwrap();
444         let wbuf0 = vec![0; 4];
445         let wbuf1 = vec![0; 8];
446         let wbufs = [IoSlice::new(&wbuf0), IoSlice::new(&wbuf1)];
447         let aiocb = AioWritev::new(
448             f.as_fd(),
449             2, //offset
450             &wbufs,
451             42, //priority
452             SigevNotify::SigevSignal {
453                 signal: Signal::SIGUSR2,
454                 si_value: 99,
455             },
456         );
457         assert_eq!(f.as_raw_fd(), aiocb.fd().as_raw_fd());
458         assert_eq!(2, aiocb.iovlen());
459         assert_eq!(2, aiocb.offset());
460         assert_eq!(42, aiocb.priority());
461         let sev = aiocb.sigevent().sigevent();
462         assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo);
463         assert_eq!(99, sev.sigev_value.sival_ptr as i64);
464     }
465 
466     // Test a simple aio operation with no completion notification.  We must
467     // poll for completion.
468     #[test]
469     #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
ok()470     fn ok() {
471         const INITIAL: &[u8] = b"abcdef123456";
472         let wbuf0 = b"BC";
473         let wbuf1 = b"DEF";
474         let wbufs = [IoSlice::new(wbuf0), IoSlice::new(wbuf1)];
475         let wlen = wbuf0.len() + wbuf1.len();
476         let mut rbuf = Vec::new();
477         const EXPECT: &[u8] = b"aBCDEF123456";
478 
479         let mut f = tempfile().unwrap();
480         f.write_all(INITIAL).unwrap();
481         {
482             let mut aiow = Box::pin(AioWritev::new(
483                 f.as_fd(),
484                 1,
485                 &wbufs,
486                 0,
487                 SigevNotify::SigevNone,
488             ));
489             aiow.as_mut().submit().unwrap();
490 
491             let err = poll_aio!(&mut aiow);
492             assert_eq!(err, Ok(()));
493             assert_eq!(aiow.as_mut().aio_return().unwrap(), wlen);
494         }
495 
496         f.rewind().unwrap();
497         let len = f.read_to_end(&mut rbuf).unwrap();
498         assert_eq!(len, EXPECT.len());
499         assert_eq!(rbuf, EXPECT);
500     }
501 }
502 
503 // Test an aio operation with completion delivered by a signal
504 #[test]
505 #[cfg_attr(
506     any(
507         all(target_env = "musl", target_arch = "x86_64"),
508         target_arch = "mips",
509         target_arch = "mips32r6",
510         target_arch = "mips64",
511         target_arch = "mips64r6"
512     ),
513     ignore
514 )]
sigev_signal()515 fn sigev_signal() {
516     let _m = crate::SIGNAL_MTX.lock();
517     let sa = SigAction::new(
518         SigHandler::Handler(sigfunc),
519         SaFlags::SA_RESETHAND,
520         SigSet::empty(),
521     );
522     SIGNALED.store(false, Ordering::Relaxed);
523     unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap();
524 
525     const INITIAL: &[u8] = b"abcdef123456";
526     const WBUF: &[u8] = b"CDEF";
527     let mut rbuf = Vec::new();
528     const EXPECT: &[u8] = b"abCDEF123456";
529 
530     let mut f = tempfile().unwrap();
531     f.write_all(INITIAL).unwrap();
532     {
533         let mut aiow = Box::pin(AioWrite::new(
534             f.as_fd(),
535             2, //offset
536             WBUF,
537             0, //priority
538             SigevNotify::SigevSignal {
539                 signal: Signal::SIGUSR2,
540                 si_value: 0, //TODO: validate in sigfunc
541             },
542         ));
543         aiow.as_mut().submit().unwrap();
544         while !SIGNALED.load(Ordering::Relaxed) {
545             thread::sleep(time::Duration::from_millis(10));
546         }
547 
548         assert_eq!(aiow.as_mut().aio_return().unwrap(), WBUF.len());
549     }
550 
551     f.rewind().unwrap();
552     let len = f.read_to_end(&mut rbuf).unwrap();
553     assert_eq!(len, EXPECT.len());
554     assert_eq!(rbuf, EXPECT);
555 }
556 
557 // Tests using aio_cancel_all for all outstanding IOs.
558 #[test]
559 #[cfg_attr(target_env = "musl", ignore)]
test_aio_cancel_all()560 fn test_aio_cancel_all() {
561     let wbuf: &[u8] = b"CDEF";
562 
563     let f = tempfile().unwrap();
564     let mut aiocb = Box::pin(AioWrite::new(
565         f.as_fd(),
566         0, //offset
567         wbuf,
568         0, //priority
569         SigevNotify::SigevNone,
570     ));
571     aiocb.as_mut().submit().unwrap();
572     let err = aiocb.as_mut().error();
573     assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS));
574 
575     aio_cancel_all(f.as_fd()).unwrap();
576 
577     // Wait for aiocb to complete, but don't care whether it succeeded
578     let _ = poll_aio!(&mut aiocb);
579     let _ = aiocb.as_mut().aio_return();
580 }
581 
582 #[test]
test_aio_suspend()583 fn test_aio_suspend() {
584     const INITIAL: &[u8] = b"abcdef123456";
585     const WBUF: &[u8] = b"CDEFG";
586     let timeout = TimeSpec::seconds(10);
587     let mut rbuf = vec![0; 4];
588     let rlen = rbuf.len();
589     let mut f = tempfile().unwrap();
590     f.write_all(INITIAL).unwrap();
591 
592     let mut wcb = Box::pin(AioWrite::new(
593         f.as_fd(),
594         2, //offset
595         WBUF,
596         0, //priority
597         SigevNotify::SigevNone,
598     ));
599 
600     let mut rcb = Box::pin(AioRead::new(
601         f.as_fd(),
602         8, //offset
603         &mut rbuf,
604         0, //priority
605         SigevNotify::SigevNone,
606     ));
607     wcb.as_mut().submit().unwrap();
608     rcb.as_mut().submit().unwrap();
609     loop {
610         {
611             let cbbuf = [
612                 &*wcb as &dyn AsRef<libc::aiocb>,
613                 &*rcb as &dyn AsRef<libc::aiocb>,
614             ];
615             let r = aio_suspend(&cbbuf[..], Some(timeout));
616             match r {
617                 Err(Errno::EINTR) => continue,
618                 Err(e) => panic!("aio_suspend returned {e:?}"),
619                 Ok(_) => (),
620             };
621         }
622         if rcb.as_mut().error() != Err(Errno::EINPROGRESS)
623             && wcb.as_mut().error() != Err(Errno::EINPROGRESS)
624         {
625             break;
626         }
627     }
628 
629     assert_eq!(wcb.as_mut().aio_return().unwrap(), WBUF.len());
630     assert_eq!(rcb.as_mut().aio_return().unwrap(), rlen);
631 }
632 
633 /// aio_suspend relies on casting Rust Aio* struct pointers to libc::aiocb
634 /// pointers.  This test ensures that such casts are valid.
635 #[test]
casting()636 fn casting() {
637     let sev = SigevNotify::SigevNone;
638     // Only safe because we'll never await the futures
639     let fd = unsafe { BorrowedFd::borrow_raw(666) };
640     let aiof = AioFsync::new(fd, AioFsyncMode::O_SYNC, 0, sev);
641     assert_eq!(
642         aiof.as_ref() as *const libc::aiocb,
643         &aiof as *const AioFsync as *const libc::aiocb
644     );
645 
646     let mut rbuf = [];
647     let aior = AioRead::new(fd, 0, &mut rbuf, 0, sev);
648     assert_eq!(
649         aior.as_ref() as *const libc::aiocb,
650         &aior as *const AioRead as *const libc::aiocb
651     );
652 
653     let wbuf = [];
654     let aiow = AioWrite::new(fd, 0, &wbuf, 0, sev);
655     assert_eq!(
656         aiow.as_ref() as *const libc::aiocb,
657         &aiow as *const AioWrite as *const libc::aiocb
658     );
659 }
660 
661 #[cfg(target_os = "freebsd")]
662 #[test]
casting_vectored()663 fn casting_vectored() {
664     use std::io::{IoSlice, IoSliceMut};
665 
666     let sev = SigevNotify::SigevNone;
667 
668     let mut rbuf = [];
669     let mut rbufs = [IoSliceMut::new(&mut rbuf)];
670     // Only safe because we'll never await the futures
671     let fd = unsafe { BorrowedFd::borrow_raw(666) };
672     let aiorv = AioReadv::new(fd, 0, &mut rbufs[..], 0, sev);
673     assert_eq!(
674         aiorv.as_ref() as *const libc::aiocb,
675         &aiorv as *const AioReadv as *const libc::aiocb
676     );
677 
678     let wbuf = [];
679     let wbufs = [IoSlice::new(&wbuf)];
680     let aiowv = AioWritev::new(fd, 0, &wbufs, 0, sev);
681     assert_eq!(
682         aiowv.as_ref() as *const libc::aiocb,
683         &aiowv as *const AioWritev as *const libc::aiocb
684     );
685 }
686