1 use libc::{c_int, c_void};
2 use nix::Result;
3 use nix::errno::*;
4 use nix::sys::aio::*;
5 use nix::sys::signal::{SaFlags, SigAction, sigaction, SigevNotify, SigHandler, Signal, SigSet};
6 use nix::sys::time::{TimeSpec, TimeValLike};
7 use std::io::{Write, Read, Seek, SeekFrom};
8 use std::ops::Deref;
9 use std::os::unix::io::AsRawFd;
10 use std::pin::Pin;
11 use std::sync::atomic::{AtomicBool, Ordering};
12 use std::{thread, time};
13 use tempfile::tempfile;
14
15 // Helper that polls an AioCb for completion or error
poll_aio(aiocb: &mut Pin<Box<AioCb>>) -> Result<()>16 fn poll_aio(aiocb: &mut Pin<Box<AioCb>>) -> Result<()> {
17 loop {
18 let err = aiocb.error();
19 if err != Err(Errno::EINPROGRESS) { return err; };
20 thread::sleep(time::Duration::from_millis(10));
21 }
22 }
23
24 // Helper that polls a component of an LioCb for completion or error
25 #[cfg(not(any(target_os = "ios", target_os = "macos")))]
poll_lio(liocb: &mut LioCb, i: usize) -> Result<()>26 fn poll_lio(liocb: &mut LioCb, i: usize) -> Result<()> {
27 loop {
28 let err = liocb.error(i);
29 if err != Err(Errno::EINPROGRESS) { return err; };
30 thread::sleep(time::Duration::from_millis(10));
31 }
32 }
33
34 #[test]
test_accessors()35 fn test_accessors() {
36 let mut rbuf = vec![0; 4];
37 let aiocb = AioCb::from_mut_slice( 1001,
38 2, //offset
39 &mut rbuf,
40 42, //priority
41 SigevNotify::SigevSignal {
42 signal: Signal::SIGUSR2,
43 si_value: 99
44 },
45 LioOpcode::LIO_NOP);
46 assert_eq!(1001, aiocb.fd());
47 assert_eq!(Some(LioOpcode::LIO_NOP), aiocb.lio_opcode());
48 assert_eq!(4, aiocb.nbytes());
49 assert_eq!(2, aiocb.offset());
50 assert_eq!(42, aiocb.priority());
51 let sev = aiocb.sigevent().sigevent();
52 assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo);
53 assert_eq!(99, sev.sigev_value.sival_ptr as i64);
54 }
55
56 // Tests AioCb.cancel. We aren't trying to test the OS's implementation, only
57 // our bindings. So it's sufficient to check that AioCb.cancel returned any
58 // AioCancelStat value.
59 #[test]
60 #[cfg_attr(target_env = "musl", ignore)]
test_cancel()61 fn test_cancel() {
62 let wbuf: &[u8] = b"CDEF";
63
64 let f = tempfile().unwrap();
65 let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
66 0, //offset
67 wbuf,
68 0, //priority
69 SigevNotify::SigevNone,
70 LioOpcode::LIO_NOP);
71 aiocb.write().unwrap();
72 let err = aiocb.error();
73 assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS));
74
75 let cancelstat = aiocb.cancel();
76 assert!(cancelstat.is_ok());
77
78 // Wait for aiocb to complete, but don't care whether it succeeded
79 let _ = poll_aio(&mut aiocb);
80 let _ = aiocb.aio_return();
81 }
82
83 // Tests using aio_cancel_all for all outstanding IOs.
84 #[test]
85 #[cfg_attr(target_env = "musl", ignore)]
test_aio_cancel_all()86 fn test_aio_cancel_all() {
87 let wbuf: &[u8] = b"CDEF";
88
89 let f = tempfile().unwrap();
90 let mut aiocb = AioCb::from_slice(f.as_raw_fd(),
91 0, //offset
92 wbuf,
93 0, //priority
94 SigevNotify::SigevNone,
95 LioOpcode::LIO_NOP);
96 aiocb.write().unwrap();
97 let err = aiocb.error();
98 assert!(err == Ok(()) || err == Err(Errno::EINPROGRESS));
99
100 let cancelstat = aio_cancel_all(f.as_raw_fd());
101 assert!(cancelstat.is_ok());
102
103 // Wait for aiocb to complete, but don't care whether it succeeded
104 let _ = poll_aio(&mut aiocb);
105 let _ = aiocb.aio_return();
106 }
107
108 #[test]
109 #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
test_fsync()110 fn test_fsync() {
111 const INITIAL: &[u8] = b"abcdef123456";
112 let mut f = tempfile().unwrap();
113 f.write_all(INITIAL).unwrap();
114 let mut aiocb = AioCb::from_fd( f.as_raw_fd(),
115 0, //priority
116 SigevNotify::SigevNone);
117 let err = aiocb.fsync(AioFsyncMode::O_SYNC);
118 assert!(err.is_ok());
119 poll_aio(&mut aiocb).unwrap();
120 aiocb.aio_return().unwrap();
121 }
122
123 /// `AioCb::fsync` should not modify the `AioCb` object if `libc::aio_fsync` returns
124 /// an error
125 // Skip on Linux, because Linux's AIO implementation can't detect errors
126 // synchronously
127 #[test]
128 #[cfg(any(target_os = "freebsd", target_os = "macos"))]
test_fsync_error()129 fn test_fsync_error() {
130 use std::mem;
131
132 const INITIAL: &[u8] = b"abcdef123456";
133 // Create an invalid AioFsyncMode
134 let mode = unsafe { mem::transmute(666) };
135 let mut f = tempfile().unwrap();
136 f.write_all(INITIAL).unwrap();
137 let mut aiocb = AioCb::from_fd( f.as_raw_fd(),
138 0, //priority
139 SigevNotify::SigevNone);
140 let err = aiocb.fsync(mode);
141 assert!(err.is_err());
142 }
143
144 #[test]
145 // On Cirrus on Linux, this test fails due to a glibc bug.
146 // https://github.com/nix-rust/nix/issues/1099
147 #[cfg_attr(target_os = "linux", ignore)]
148 // On Cirrus, aio_suspend is failing with EINVAL
149 // https://github.com/nix-rust/nix/issues/1361
150 #[cfg_attr(target_os = "macos", ignore)]
test_aio_suspend()151 fn test_aio_suspend() {
152 const INITIAL: &[u8] = b"abcdef123456";
153 const WBUF: &[u8] = b"CDEFG";
154 let timeout = TimeSpec::seconds(10);
155 let mut rbuf = vec![0; 4];
156 let rlen = rbuf.len();
157 let mut f = tempfile().unwrap();
158 f.write_all(INITIAL).unwrap();
159
160 let mut wcb = AioCb::from_slice( f.as_raw_fd(),
161 2, //offset
162 WBUF,
163 0, //priority
164 SigevNotify::SigevNone,
165 LioOpcode::LIO_WRITE);
166
167 let mut rcb = AioCb::from_mut_slice( f.as_raw_fd(),
168 8, //offset
169 &mut rbuf,
170 0, //priority
171 SigevNotify::SigevNone,
172 LioOpcode::LIO_READ);
173 wcb.write().unwrap();
174 rcb.read().unwrap();
175 loop {
176 {
177 let cbbuf = [wcb.as_ref(), rcb.as_ref()];
178 let r = aio_suspend(&cbbuf[..], Some(timeout));
179 match r {
180 Err(Errno::EINTR) => continue,
181 Err(e) => panic!("aio_suspend returned {:?}", e),
182 Ok(_) => ()
183 };
184 }
185 if rcb.error() != Err(Errno::EINPROGRESS) &&
186 wcb.error() != Err(Errno::EINPROGRESS) {
187 break
188 }
189 }
190
191 assert_eq!(wcb.aio_return().unwrap() as usize, WBUF.len());
192 assert_eq!(rcb.aio_return().unwrap() as usize, rlen);
193 }
194
195 // Test a simple aio operation with no completion notification. We must poll
196 // for completion
197 #[test]
198 #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
test_read()199 fn test_read() {
200 const INITIAL: &[u8] = b"abcdef123456";
201 let mut rbuf = vec![0; 4];
202 const EXPECT: &[u8] = b"cdef";
203 let mut f = tempfile().unwrap();
204 f.write_all(INITIAL).unwrap();
205 {
206 let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(),
207 2, //offset
208 &mut rbuf,
209 0, //priority
210 SigevNotify::SigevNone,
211 LioOpcode::LIO_NOP);
212 aiocb.read().unwrap();
213
214 let err = poll_aio(&mut aiocb);
215 assert_eq!(err, Ok(()));
216 assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len());
217 }
218
219 assert_eq!(EXPECT, rbuf.deref().deref());
220 }
221
222 /// `AioCb::read` should not modify the `AioCb` object if `libc::aio_read`
223 /// returns an error
224 // Skip on Linux, because Linux's AIO implementation can't detect errors
225 // synchronously
226 #[test]
227 #[cfg(any(target_os = "freebsd", target_os = "macos"))]
test_read_error()228 fn test_read_error() {
229 const INITIAL: &[u8] = b"abcdef123456";
230 let mut rbuf = vec![0; 4];
231 let mut f = tempfile().unwrap();
232 f.write_all(INITIAL).unwrap();
233 let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(),
234 -1, //an invalid offset
235 &mut rbuf,
236 0, //priority
237 SigevNotify::SigevNone,
238 LioOpcode::LIO_NOP);
239 assert!(aiocb.read().is_err());
240 }
241
242 // Tests from_mut_slice
243 #[test]
244 #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
test_read_into_mut_slice()245 fn test_read_into_mut_slice() {
246 const INITIAL: &[u8] = b"abcdef123456";
247 let mut rbuf = vec![0; 4];
248 const EXPECT: &[u8] = b"cdef";
249 let mut f = tempfile().unwrap();
250 f.write_all(INITIAL).unwrap();
251 {
252 let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(),
253 2, //offset
254 &mut rbuf,
255 0, //priority
256 SigevNotify::SigevNone,
257 LioOpcode::LIO_NOP);
258 aiocb.read().unwrap();
259
260 let err = poll_aio(&mut aiocb);
261 assert_eq!(err, Ok(()));
262 assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len());
263 }
264
265 assert_eq!(rbuf, EXPECT);
266 }
267
268 // Tests from_ptr
269 #[test]
270 #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
test_read_into_pointer()271 fn test_read_into_pointer() {
272 const INITIAL: &[u8] = b"abcdef123456";
273 let mut rbuf = vec![0; 4];
274 const EXPECT: &[u8] = b"cdef";
275 let mut f = tempfile().unwrap();
276 f.write_all(INITIAL).unwrap();
277 {
278 // Safety: ok because rbuf lives until after poll_aio
279 let mut aiocb = unsafe {
280 AioCb::from_mut_ptr( f.as_raw_fd(),
281 2, //offset
282 rbuf.as_mut_ptr() as *mut c_void,
283 rbuf.len(),
284 0, //priority
285 SigevNotify::SigevNone,
286 LioOpcode::LIO_NOP)
287 };
288 aiocb.read().unwrap();
289
290 let err = poll_aio(&mut aiocb);
291 assert_eq!(err, Ok(()));
292 assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len());
293 }
294
295 assert_eq!(rbuf, EXPECT);
296 }
297
298 // Test reading into an immutable buffer. It should fail
299 // FIXME: This test fails to panic on Linux/musl
300 #[test]
301 #[should_panic(expected = "Can't read into an immutable buffer")]
302 #[cfg_attr(target_env = "musl", ignore)]
test_read_immutable_buffer()303 fn test_read_immutable_buffer() {
304 let rbuf: &[u8] = b"CDEF";
305 let f = tempfile().unwrap();
306 let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
307 2, //offset
308 rbuf,
309 0, //priority
310 SigevNotify::SigevNone,
311 LioOpcode::LIO_NOP);
312 aiocb.read().unwrap();
313 }
314
315
316 // Test a simple aio operation with no completion notification. We must poll
317 // for completion. Unlike test_aio_read, this test uses AioCb::from_slice
318 #[test]
319 #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
test_write()320 fn test_write() {
321 const INITIAL: &[u8] = b"abcdef123456";
322 let wbuf = "CDEF".to_string().into_bytes();
323 let mut rbuf = Vec::new();
324 const EXPECT: &[u8] = b"abCDEF123456";
325
326 let mut f = tempfile().unwrap();
327 f.write_all(INITIAL).unwrap();
328 let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
329 2, //offset
330 &wbuf,
331 0, //priority
332 SigevNotify::SigevNone,
333 LioOpcode::LIO_NOP);
334 aiocb.write().unwrap();
335
336 let err = poll_aio(&mut aiocb);
337 assert_eq!(err, Ok(()));
338 assert_eq!(aiocb.aio_return().unwrap() as usize, wbuf.len());
339
340 f.seek(SeekFrom::Start(0)).unwrap();
341 let len = f.read_to_end(&mut rbuf).unwrap();
342 assert_eq!(len, EXPECT.len());
343 assert_eq!(rbuf, EXPECT);
344 }
345
346 // Tests `AioCb::from_ptr`
347 #[test]
348 #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
test_write_from_pointer()349 fn test_write_from_pointer() {
350 const INITIAL: &[u8] = b"abcdef123456";
351 let wbuf = "CDEF".to_string().into_bytes();
352 let mut rbuf = Vec::new();
353 const EXPECT: &[u8] = b"abCDEF123456";
354
355 let mut f = tempfile().unwrap();
356 f.write_all(INITIAL).unwrap();
357 // Safety: ok because aiocb outlives poll_aio
358 let mut aiocb = unsafe {
359 AioCb::from_ptr( f.as_raw_fd(),
360 2, //offset
361 wbuf.as_ptr() as *const c_void,
362 wbuf.len(),
363 0, //priority
364 SigevNotify::SigevNone,
365 LioOpcode::LIO_NOP)
366 };
367 aiocb.write().unwrap();
368
369 let err = poll_aio(&mut aiocb);
370 assert_eq!(err, Ok(()));
371 assert_eq!(aiocb.aio_return().unwrap() as usize, wbuf.len());
372
373 f.seek(SeekFrom::Start(0)).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 /// `AioCb::write` should not modify the `AioCb` object if `libc::aio_write`
380 /// returns an error
381 // Skip on Linux, because Linux's AIO implementation can't detect errors
382 // synchronously
383 #[test]
384 #[cfg(any(target_os = "freebsd", target_os = "macos"))]
test_write_error()385 fn test_write_error() {
386 let wbuf = "CDEF".to_string().into_bytes();
387 let mut aiocb = AioCb::from_slice( 666, // An invalid file descriptor
388 0, //offset
389 &wbuf,
390 0, //priority
391 SigevNotify::SigevNone,
392 LioOpcode::LIO_NOP);
393 assert!(aiocb.write().is_err());
394 }
395
396 lazy_static! {
397 pub static ref SIGNALED: AtomicBool = AtomicBool::new(false);
398 }
399
sigfunc(_: c_int)400 extern fn sigfunc(_: c_int) {
401 SIGNALED.store(true, Ordering::Relaxed);
402 }
403
404 // Test an aio operation with completion delivered by a signal
405 // FIXME: This test is ignored on mips because of failures in qemu in CI
406 #[test]
407 #[cfg_attr(any(all(target_env = "musl", target_arch = "x86_64"), target_arch = "mips", target_arch = "mips64"), ignore)]
test_write_sigev_signal()408 fn test_write_sigev_signal() {
409 let _m = crate::SIGNAL_MTX.lock();
410 let sa = SigAction::new(SigHandler::Handler(sigfunc),
411 SaFlags::SA_RESETHAND,
412 SigSet::empty());
413 SIGNALED.store(false, Ordering::Relaxed);
414 unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap();
415
416 const INITIAL: &[u8] = b"abcdef123456";
417 const WBUF: &[u8] = b"CDEF";
418 let mut rbuf = Vec::new();
419 const EXPECT: &[u8] = b"abCDEF123456";
420
421 let mut f = tempfile().unwrap();
422 f.write_all(INITIAL).unwrap();
423 let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
424 2, //offset
425 WBUF,
426 0, //priority
427 SigevNotify::SigevSignal {
428 signal: Signal::SIGUSR2,
429 si_value: 0 //TODO: validate in sigfunc
430 },
431 LioOpcode::LIO_NOP);
432 aiocb.write().unwrap();
433 while !SIGNALED.load(Ordering::Relaxed) {
434 thread::sleep(time::Duration::from_millis(10));
435 }
436
437 assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
438 f.seek(SeekFrom::Start(0)).unwrap();
439 let len = f.read_to_end(&mut rbuf).unwrap();
440 assert_eq!(len, EXPECT.len());
441 assert_eq!(rbuf, EXPECT);
442 }
443
444 // Test LioCb::listio with LIO_WAIT, so all AIO ops should be complete by the
445 // time listio returns.
446 #[test]
447 #[cfg(not(any(target_os = "ios", target_os = "macos")))]
448 #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
test_liocb_listio_wait()449 fn test_liocb_listio_wait() {
450 const INITIAL: &[u8] = b"abcdef123456";
451 const WBUF: &[u8] = b"CDEF";
452 let mut rbuf = vec![0; 4];
453 let rlen = rbuf.len();
454 let mut rbuf2 = Vec::new();
455 const EXPECT: &[u8] = b"abCDEF123456";
456 let mut f = tempfile().unwrap();
457
458 f.write_all(INITIAL).unwrap();
459
460 {
461 let mut liocb = LioCbBuilder::with_capacity(2)
462 .emplace_slice(
463 f.as_raw_fd(),
464 2, //offset
465 WBUF,
466 0, //priority
467 SigevNotify::SigevNone,
468 LioOpcode::LIO_WRITE
469 ).emplace_mut_slice(
470 f.as_raw_fd(),
471 8, //offset
472 &mut rbuf,
473 0, //priority
474 SigevNotify::SigevNone,
475 LioOpcode::LIO_READ
476 ).finish();
477 let err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone);
478 err.expect("lio_listio");
479
480 assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len());
481 assert_eq!(liocb.aio_return(1).unwrap() as usize, rlen);
482 }
483 assert_eq!(rbuf.deref().deref(), b"3456");
484
485 f.seek(SeekFrom::Start(0)).unwrap();
486 let len = f.read_to_end(&mut rbuf2).unwrap();
487 assert_eq!(len, EXPECT.len());
488 assert_eq!(rbuf2, EXPECT);
489 }
490
491 // Test LioCb::listio with LIO_NOWAIT and no SigEvent, so we must use some other
492 // mechanism to check for the individual AioCb's completion.
493 #[test]
494 #[cfg(not(any(target_os = "ios", target_os = "macos")))]
495 #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
test_liocb_listio_nowait()496 fn test_liocb_listio_nowait() {
497 const INITIAL: &[u8] = b"abcdef123456";
498 const WBUF: &[u8] = b"CDEF";
499 let mut rbuf = vec![0; 4];
500 let rlen = rbuf.len();
501 let mut rbuf2 = Vec::new();
502 const EXPECT: &[u8] = b"abCDEF123456";
503 let mut f = tempfile().unwrap();
504
505 f.write_all(INITIAL).unwrap();
506
507 {
508 let mut liocb = LioCbBuilder::with_capacity(2)
509 .emplace_slice(
510 f.as_raw_fd(),
511 2, //offset
512 WBUF,
513 0, //priority
514 SigevNotify::SigevNone,
515 LioOpcode::LIO_WRITE
516 ).emplace_mut_slice(
517 f.as_raw_fd(),
518 8, //offset
519 &mut rbuf,
520 0, //priority
521 SigevNotify::SigevNone,
522 LioOpcode::LIO_READ
523 ).finish();
524 let err = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone);
525 err.expect("lio_listio");
526
527 poll_lio(&mut liocb, 0).unwrap();
528 poll_lio(&mut liocb, 1).unwrap();
529 assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len());
530 assert_eq!(liocb.aio_return(1).unwrap() as usize, rlen);
531 }
532 assert_eq!(rbuf.deref().deref(), b"3456");
533
534 f.seek(SeekFrom::Start(0)).unwrap();
535 let len = f.read_to_end(&mut rbuf2).unwrap();
536 assert_eq!(len, EXPECT.len());
537 assert_eq!(rbuf2, EXPECT);
538 }
539
540 // Test LioCb::listio with LIO_NOWAIT and a SigEvent to indicate when all
541 // AioCb's are complete.
542 // FIXME: This test is ignored on mips/mips64 because of failures in qemu in CI.
543 #[test]
544 #[cfg(not(any(target_os = "ios", target_os = "macos")))]
545 #[cfg_attr(any(target_arch = "mips", target_arch = "mips64", target_env = "musl"), ignore)]
test_liocb_listio_signal()546 fn test_liocb_listio_signal() {
547 let _m = crate::SIGNAL_MTX.lock();
548 const INITIAL: &[u8] = b"abcdef123456";
549 const WBUF: &[u8] = b"CDEF";
550 let mut rbuf = vec![0; 4];
551 let rlen = rbuf.len();
552 let mut rbuf2 = Vec::new();
553 const EXPECT: &[u8] = b"abCDEF123456";
554 let mut f = tempfile().unwrap();
555 let sa = SigAction::new(SigHandler::Handler(sigfunc),
556 SaFlags::SA_RESETHAND,
557 SigSet::empty());
558 let sigev_notify = SigevNotify::SigevSignal { signal: Signal::SIGUSR2,
559 si_value: 0 };
560
561 f.write_all(INITIAL).unwrap();
562
563 {
564 let mut liocb = LioCbBuilder::with_capacity(2)
565 .emplace_slice(
566 f.as_raw_fd(),
567 2, //offset
568 WBUF,
569 0, //priority
570 SigevNotify::SigevNone,
571 LioOpcode::LIO_WRITE
572 ).emplace_mut_slice(
573 f.as_raw_fd(),
574 8, //offset
575 &mut rbuf,
576 0, //priority
577 SigevNotify::SigevNone,
578 LioOpcode::LIO_READ
579 ).finish();
580 SIGNALED.store(false, Ordering::Relaxed);
581 unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap();
582 let err = liocb.listio(LioMode::LIO_NOWAIT, sigev_notify);
583 err.expect("lio_listio");
584 while !SIGNALED.load(Ordering::Relaxed) {
585 thread::sleep(time::Duration::from_millis(10));
586 }
587
588 assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len());
589 assert_eq!(liocb.aio_return(1).unwrap() as usize, rlen);
590 }
591 assert_eq!(rbuf.deref().deref(), b"3456");
592
593 f.seek(SeekFrom::Start(0)).unwrap();
594 let len = f.read_to_end(&mut rbuf2).unwrap();
595 assert_eq!(len, EXPECT.len());
596 assert_eq!(rbuf2, EXPECT);
597 }
598
599 // Try to use LioCb::listio to read into an immutable buffer. It should fail
600 // FIXME: This test fails to panic on Linux/musl
601 #[test]
602 #[cfg(not(any(target_os = "ios", target_os = "macos")))]
603 #[should_panic(expected = "Can't read into an immutable buffer")]
604 #[cfg_attr(target_env = "musl", ignore)]
test_liocb_listio_read_immutable()605 fn test_liocb_listio_read_immutable() {
606 let rbuf: &[u8] = b"abcd";
607 let f = tempfile().unwrap();
608
609
610 let mut liocb = LioCbBuilder::with_capacity(1)
611 .emplace_slice(
612 f.as_raw_fd(),
613 2, //offset
614 rbuf,
615 0, //priority
616 SigevNotify::SigevNone,
617 LioOpcode::LIO_READ
618 ).finish();
619 let _ = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone);
620 }
621