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