1 use libc::{c_int, c_void}; 2 use nix::{Error, 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 16 fn poll_aio(aiocb: &mut Pin<Box<AioCb>>) -> Result<()> { 17 loop { 18 let err = aiocb.error(); 19 if err != Err(Error::from(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")))] 26 fn poll_lio(liocb: &mut LioCb, i: usize) -> Result<()> { 27 loop { 28 let err = liocb.error(i); 29 if err != Err(Error::from(Errno::EINPROGRESS)) { return err; }; 30 thread::sleep(time::Duration::from_millis(10)); 31 } 32 } 33 34 #[test] 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)] 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(Error::from(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)] 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(Error::from(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)] 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"))] 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 #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] 146 // On Travis, aio_suspend hits an assertion within glibc. This is either a bug 147 // in Travis's version of glibc or Linux. Either way, we must skip the test. 148 // https://github.com/nix-rust/nix/issues/1099 149 #[cfg_attr(target_os = "linux", ignore)] 150 // On Cirrus, aio_suspend is failing with EINVAL 151 // https://github.com/nix-rust/nix/issues/1361 152 #[cfg_attr(target_os = "macos", ignore)] 153 fn test_aio_suspend() { 154 const INITIAL: &[u8] = b"abcdef123456"; 155 const WBUF: &[u8] = b"CDEFG"; 156 let timeout = TimeSpec::seconds(10); 157 let mut rbuf = vec![0; 4]; 158 let rlen = rbuf.len(); 159 let mut f = tempfile().unwrap(); 160 f.write_all(INITIAL).unwrap(); 161 162 let mut wcb = AioCb::from_slice( f.as_raw_fd(), 163 2, //offset 164 WBUF, 165 0, //priority 166 SigevNotify::SigevNone, 167 LioOpcode::LIO_WRITE); 168 169 let mut rcb = AioCb::from_mut_slice( f.as_raw_fd(), 170 8, //offset 171 &mut rbuf, 172 0, //priority 173 SigevNotify::SigevNone, 174 LioOpcode::LIO_READ); 175 wcb.write().unwrap(); 176 rcb.read().unwrap(); 177 loop { 178 { 179 let cbbuf = [wcb.as_ref(), rcb.as_ref()]; 180 let r = aio_suspend(&cbbuf[..], Some(timeout)); 181 match r { 182 Err(Error::Sys(Errno::EINTR)) => continue, 183 Err(e) => panic!("aio_suspend returned {:?}", e), 184 Ok(_) => () 185 }; 186 } 187 if rcb.error() != Err(Error::from(Errno::EINPROGRESS)) && 188 wcb.error() != Err(Error::from(Errno::EINPROGRESS)) { 189 break 190 } 191 } 192 193 assert_eq!(wcb.aio_return().unwrap() as usize, WBUF.len()); 194 assert_eq!(rcb.aio_return().unwrap() as usize, rlen); 195 } 196 197 // Test a simple aio operation with no completion notification. We must poll 198 // for completion 199 #[test] 200 #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] 201 fn test_read() { 202 const INITIAL: &[u8] = b"abcdef123456"; 203 let mut rbuf = vec![0; 4]; 204 const EXPECT: &[u8] = b"cdef"; 205 let mut f = tempfile().unwrap(); 206 f.write_all(INITIAL).unwrap(); 207 { 208 let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(), 209 2, //offset 210 &mut rbuf, 211 0, //priority 212 SigevNotify::SigevNone, 213 LioOpcode::LIO_NOP); 214 aiocb.read().unwrap(); 215 216 let err = poll_aio(&mut aiocb); 217 assert_eq!(err, Ok(())); 218 assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len()); 219 } 220 221 assert_eq!(EXPECT, rbuf.deref().deref()); 222 } 223 224 /// `AioCb::read` should not modify the `AioCb` object if `libc::aio_read` 225 /// returns an error 226 // Skip on Linux, because Linux's AIO implementation can't detect errors 227 // synchronously 228 #[test] 229 #[cfg(any(target_os = "freebsd", target_os = "macos"))] 230 fn test_read_error() { 231 const INITIAL: &[u8] = b"abcdef123456"; 232 let mut rbuf = vec![0; 4]; 233 let mut f = tempfile().unwrap(); 234 f.write_all(INITIAL).unwrap(); 235 let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(), 236 -1, //an invalid offset 237 &mut rbuf, 238 0, //priority 239 SigevNotify::SigevNone, 240 LioOpcode::LIO_NOP); 241 assert!(aiocb.read().is_err()); 242 } 243 244 // Tests from_mut_slice 245 #[test] 246 #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] 247 fn test_read_into_mut_slice() { 248 const INITIAL: &[u8] = b"abcdef123456"; 249 let mut rbuf = vec![0; 4]; 250 const EXPECT: &[u8] = b"cdef"; 251 let mut f = tempfile().unwrap(); 252 f.write_all(INITIAL).unwrap(); 253 { 254 let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(), 255 2, //offset 256 &mut rbuf, 257 0, //priority 258 SigevNotify::SigevNone, 259 LioOpcode::LIO_NOP); 260 aiocb.read().unwrap(); 261 262 let err = poll_aio(&mut aiocb); 263 assert_eq!(err, Ok(())); 264 assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len()); 265 } 266 267 assert_eq!(rbuf, EXPECT); 268 } 269 270 // Tests from_ptr 271 #[test] 272 #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] 273 fn test_read_into_pointer() { 274 const INITIAL: &[u8] = b"abcdef123456"; 275 let mut rbuf = vec![0; 4]; 276 const EXPECT: &[u8] = b"cdef"; 277 let mut f = tempfile().unwrap(); 278 f.write_all(INITIAL).unwrap(); 279 { 280 // Safety: ok because rbuf lives until after poll_aio 281 let mut aiocb = unsafe { 282 AioCb::from_mut_ptr( f.as_raw_fd(), 283 2, //offset 284 rbuf.as_mut_ptr() as *mut c_void, 285 rbuf.len(), 286 0, //priority 287 SigevNotify::SigevNone, 288 LioOpcode::LIO_NOP) 289 }; 290 aiocb.read().unwrap(); 291 292 let err = poll_aio(&mut aiocb); 293 assert_eq!(err, Ok(())); 294 assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len()); 295 } 296 297 assert_eq!(rbuf, EXPECT); 298 } 299 300 // Test reading into an immutable buffer. It should fail 301 // FIXME: This test fails to panic on Linux/musl 302 #[test] 303 #[should_panic(expected = "Can't read into an immutable buffer")] 304 #[cfg_attr(target_env = "musl", ignore)] 305 fn test_read_immutable_buffer() { 306 let rbuf: &[u8] = b"CDEF"; 307 let f = tempfile().unwrap(); 308 let mut aiocb = AioCb::from_slice( f.as_raw_fd(), 309 2, //offset 310 rbuf, 311 0, //priority 312 SigevNotify::SigevNone, 313 LioOpcode::LIO_NOP); 314 aiocb.read().unwrap(); 315 } 316 317 318 // Test a simple aio operation with no completion notification. We must poll 319 // for completion. Unlike test_aio_read, this test uses AioCb::from_slice 320 #[test] 321 #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] 322 fn test_write() { 323 const INITIAL: &[u8] = b"abcdef123456"; 324 let wbuf = "CDEF".to_string().into_bytes(); 325 let mut rbuf = Vec::new(); 326 const EXPECT: &[u8] = b"abCDEF123456"; 327 328 let mut f = tempfile().unwrap(); 329 f.write_all(INITIAL).unwrap(); 330 let mut aiocb = AioCb::from_slice( f.as_raw_fd(), 331 2, //offset 332 &wbuf, 333 0, //priority 334 SigevNotify::SigevNone, 335 LioOpcode::LIO_NOP); 336 aiocb.write().unwrap(); 337 338 let err = poll_aio(&mut aiocb); 339 assert_eq!(err, Ok(())); 340 assert_eq!(aiocb.aio_return().unwrap() as usize, wbuf.len()); 341 342 f.seek(SeekFrom::Start(0)).unwrap(); 343 let len = f.read_to_end(&mut rbuf).unwrap(); 344 assert_eq!(len, EXPECT.len()); 345 assert_eq!(rbuf, EXPECT); 346 } 347 348 // Tests `AioCb::from_ptr` 349 #[test] 350 #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] 351 fn test_write_from_pointer() { 352 const INITIAL: &[u8] = b"abcdef123456"; 353 let wbuf = "CDEF".to_string().into_bytes(); 354 let mut rbuf = Vec::new(); 355 const EXPECT: &[u8] = b"abCDEF123456"; 356 357 let mut f = tempfile().unwrap(); 358 f.write_all(INITIAL).unwrap(); 359 // Safety: ok because aiocb outlives poll_aio 360 let mut aiocb = unsafe { 361 AioCb::from_ptr( f.as_raw_fd(), 362 2, //offset 363 wbuf.as_ptr() as *const c_void, 364 wbuf.len(), 365 0, //priority 366 SigevNotify::SigevNone, 367 LioOpcode::LIO_NOP) 368 }; 369 aiocb.write().unwrap(); 370 371 let err = poll_aio(&mut aiocb); 372 assert_eq!(err, Ok(())); 373 assert_eq!(aiocb.aio_return().unwrap() as usize, wbuf.len()); 374 375 f.seek(SeekFrom::Start(0)).unwrap(); 376 let len = f.read_to_end(&mut rbuf).unwrap(); 377 assert_eq!(len, EXPECT.len()); 378 assert_eq!(rbuf, EXPECT); 379 } 380 381 /// `AioCb::write` should not modify the `AioCb` object if `libc::aio_write` 382 /// returns an error 383 // Skip on Linux, because Linux's AIO implementation can't detect errors 384 // synchronously 385 #[test] 386 #[cfg(any(target_os = "freebsd", target_os = "macos"))] 387 fn test_write_error() { 388 let wbuf = "CDEF".to_string().into_bytes(); 389 let mut aiocb = AioCb::from_slice( 666, // An invalid file descriptor 390 0, //offset 391 &wbuf, 392 0, //priority 393 SigevNotify::SigevNone, 394 LioOpcode::LIO_NOP); 395 assert!(aiocb.write().is_err()); 396 } 397 398 lazy_static! { 399 pub static ref SIGNALED: AtomicBool = AtomicBool::new(false); 400 } 401 402 extern fn sigfunc(_: c_int) { 403 SIGNALED.store(true, Ordering::Relaxed); 404 } 405 406 // Test an aio operation with completion delivered by a signal 407 // FIXME: This test is ignored on mips because of failures in qemu in CI 408 #[test] 409 #[cfg_attr(any(all(target_env = "musl", target_arch = "x86_64"), target_arch = "mips", target_arch = "mips64"), ignore)] 410 fn test_write_sigev_signal() { 411 let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); 412 let sa = SigAction::new(SigHandler::Handler(sigfunc), 413 SaFlags::SA_RESETHAND, 414 SigSet::empty()); 415 SIGNALED.store(false, Ordering::Relaxed); 416 unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap(); 417 418 const INITIAL: &[u8] = b"abcdef123456"; 419 const WBUF: &[u8] = b"CDEF"; 420 let mut rbuf = Vec::new(); 421 const EXPECT: &[u8] = b"abCDEF123456"; 422 423 let mut f = tempfile().unwrap(); 424 f.write_all(INITIAL).unwrap(); 425 let mut aiocb = AioCb::from_slice( f.as_raw_fd(), 426 2, //offset 427 WBUF, 428 0, //priority 429 SigevNotify::SigevSignal { 430 signal: Signal::SIGUSR2, 431 si_value: 0 //TODO: validate in sigfunc 432 }, 433 LioOpcode::LIO_NOP); 434 aiocb.write().unwrap(); 435 while !SIGNALED.load(Ordering::Relaxed) { 436 thread::sleep(time::Duration::from_millis(10)); 437 } 438 439 assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len()); 440 f.seek(SeekFrom::Start(0)).unwrap(); 441 let len = f.read_to_end(&mut rbuf).unwrap(); 442 assert_eq!(len, EXPECT.len()); 443 assert_eq!(rbuf, EXPECT); 444 } 445 446 // Test LioCb::listio with LIO_WAIT, so all AIO ops should be complete by the 447 // time listio returns. 448 #[test] 449 #[cfg(not(any(target_os = "ios", target_os = "macos")))] 450 #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] 451 fn test_liocb_listio_wait() { 452 const INITIAL: &[u8] = b"abcdef123456"; 453 const WBUF: &[u8] = b"CDEF"; 454 let mut rbuf = vec![0; 4]; 455 let rlen = rbuf.len(); 456 let mut rbuf2 = Vec::new(); 457 const EXPECT: &[u8] = b"abCDEF123456"; 458 let mut f = tempfile().unwrap(); 459 460 f.write_all(INITIAL).unwrap(); 461 462 { 463 let mut liocb = LioCbBuilder::with_capacity(2) 464 .emplace_slice( 465 f.as_raw_fd(), 466 2, //offset 467 WBUF, 468 0, //priority 469 SigevNotify::SigevNone, 470 LioOpcode::LIO_WRITE 471 ).emplace_mut_slice( 472 f.as_raw_fd(), 473 8, //offset 474 &mut rbuf, 475 0, //priority 476 SigevNotify::SigevNone, 477 LioOpcode::LIO_READ 478 ).finish(); 479 let err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone); 480 err.expect("lio_listio"); 481 482 assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len()); 483 assert_eq!(liocb.aio_return(1).unwrap() as usize, rlen); 484 } 485 assert_eq!(rbuf.deref().deref(), b"3456"); 486 487 f.seek(SeekFrom::Start(0)).unwrap(); 488 let len = f.read_to_end(&mut rbuf2).unwrap(); 489 assert_eq!(len, EXPECT.len()); 490 assert_eq!(rbuf2, EXPECT); 491 } 492 493 // Test LioCb::listio with LIO_NOWAIT and no SigEvent, so we must use some other 494 // mechanism to check for the individual AioCb's completion. 495 #[test] 496 #[cfg(not(any(target_os = "ios", target_os = "macos")))] 497 #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)] 498 fn test_liocb_listio_nowait() { 499 const INITIAL: &[u8] = b"abcdef123456"; 500 const WBUF: &[u8] = b"CDEF"; 501 let mut rbuf = vec![0; 4]; 502 let rlen = rbuf.len(); 503 let mut rbuf2 = Vec::new(); 504 const EXPECT: &[u8] = b"abCDEF123456"; 505 let mut f = tempfile().unwrap(); 506 507 f.write_all(INITIAL).unwrap(); 508 509 { 510 let mut liocb = LioCbBuilder::with_capacity(2) 511 .emplace_slice( 512 f.as_raw_fd(), 513 2, //offset 514 WBUF, 515 0, //priority 516 SigevNotify::SigevNone, 517 LioOpcode::LIO_WRITE 518 ).emplace_mut_slice( 519 f.as_raw_fd(), 520 8, //offset 521 &mut rbuf, 522 0, //priority 523 SigevNotify::SigevNone, 524 LioOpcode::LIO_READ 525 ).finish(); 526 let err = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone); 527 err.expect("lio_listio"); 528 529 poll_lio(&mut liocb, 0).unwrap(); 530 poll_lio(&mut liocb, 1).unwrap(); 531 assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len()); 532 assert_eq!(liocb.aio_return(1).unwrap() as usize, rlen); 533 } 534 assert_eq!(rbuf.deref().deref(), b"3456"); 535 536 f.seek(SeekFrom::Start(0)).unwrap(); 537 let len = f.read_to_end(&mut rbuf2).unwrap(); 538 assert_eq!(len, EXPECT.len()); 539 assert_eq!(rbuf2, EXPECT); 540 } 541 542 // Test LioCb::listio with LIO_NOWAIT and a SigEvent to indicate when all 543 // AioCb's are complete. 544 // FIXME: This test is ignored on mips/mips64 because of failures in qemu in CI. 545 #[test] 546 #[cfg(not(any(target_os = "ios", target_os = "macos")))] 547 #[cfg_attr(any(target_arch = "mips", target_arch = "mips64", target_env = "musl"), ignore)] 548 fn test_liocb_listio_signal() { 549 let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); 550 const INITIAL: &[u8] = b"abcdef123456"; 551 const WBUF: &[u8] = b"CDEF"; 552 let mut rbuf = vec![0; 4]; 553 let rlen = rbuf.len(); 554 let mut rbuf2 = Vec::new(); 555 const EXPECT: &[u8] = b"abCDEF123456"; 556 let mut f = tempfile().unwrap(); 557 let sa = SigAction::new(SigHandler::Handler(sigfunc), 558 SaFlags::SA_RESETHAND, 559 SigSet::empty()); 560 let sigev_notify = SigevNotify::SigevSignal { signal: Signal::SIGUSR2, 561 si_value: 0 }; 562 563 f.write_all(INITIAL).unwrap(); 564 565 { 566 let mut liocb = LioCbBuilder::with_capacity(2) 567 .emplace_slice( 568 f.as_raw_fd(), 569 2, //offset 570 WBUF, 571 0, //priority 572 SigevNotify::SigevNone, 573 LioOpcode::LIO_WRITE 574 ).emplace_mut_slice( 575 f.as_raw_fd(), 576 8, //offset 577 &mut rbuf, 578 0, //priority 579 SigevNotify::SigevNone, 580 LioOpcode::LIO_READ 581 ).finish(); 582 SIGNALED.store(false, Ordering::Relaxed); 583 unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap(); 584 let err = liocb.listio(LioMode::LIO_NOWAIT, sigev_notify); 585 err.expect("lio_listio"); 586 while !SIGNALED.load(Ordering::Relaxed) { 587 thread::sleep(time::Duration::from_millis(10)); 588 } 589 590 assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len()); 591 assert_eq!(liocb.aio_return(1).unwrap() as usize, rlen); 592 } 593 assert_eq!(rbuf.deref().deref(), b"3456"); 594 595 f.seek(SeekFrom::Start(0)).unwrap(); 596 let len = f.read_to_end(&mut rbuf2).unwrap(); 597 assert_eq!(len, EXPECT.len()); 598 assert_eq!(rbuf2, EXPECT); 599 } 600 601 // Try to use LioCb::listio to read into an immutable buffer. It should fail 602 // FIXME: This test fails to panic on Linux/musl 603 #[test] 604 #[cfg(not(any(target_os = "ios", target_os = "macos")))] 605 #[should_panic(expected = "Can't read into an immutable buffer")] 606 #[cfg_attr(target_env = "musl", ignore)] 607 fn test_liocb_listio_read_immutable() { 608 let rbuf: &[u8] = b"abcd"; 609 let f = tempfile().unwrap(); 610 611 612 let mut liocb = LioCbBuilder::with_capacity(1) 613 .emplace_slice( 614 f.as_raw_fd(), 615 2, //offset 616 rbuf, 617 0, //priority 618 SigevNotify::SigevNone, 619 LioOpcode::LIO_READ 620 ).finish(); 621 let _ = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone); 622 } 623