Skip to content

Enable most AIO tests on musl targets and clean them up #929

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 52 additions & 71 deletions test/sys/test_aio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use nix::sys::aio::*;
use nix::sys::signal::{SaFlags, SigAction, sigaction, SigevNotify, SigHandler, Signal, SigSet};
use nix::sys::time::{TimeSpec, TimeValLike};
use std::io::{Write, Read, Seek, SeekFrom};
use std::ops::Deref;
use std::os::unix::io::AsRawFd;
use std::sync::atomic::{AtomicBool, Ordering};
use std::{thread, time};
Expand Down Expand Up @@ -47,7 +46,6 @@ fn test_accessors() {
// our bindings. So it's sufficient to check that AioCb.cancel returned any
// AioCancelStat value.
#[test]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
fn test_cancel() {
let wbuf: &[u8] = b"CDEF";

Expand All @@ -72,7 +70,6 @@ fn test_cancel() {

// Tests using aio_cancel_all for all outstanding IOs.
#[test]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
fn test_aio_cancel_all() {
let wbuf: &[u8] = b"CDEF";

Expand All @@ -96,7 +93,6 @@ fn test_aio_cancel_all() {
}

#[test]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
fn test_fsync() {
const INITIAL: &[u8] = b"abcdef123456";
let mut f = tempfile().unwrap();
Expand Down Expand Up @@ -132,7 +128,6 @@ fn test_fsync_error() {
}

#[test]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
fn test_aio_suspend() {
const INITIAL: &[u8] = b"abcdef123456";
const WBUF: &[u8] = b"CDEFG";
Expand Down Expand Up @@ -168,14 +163,13 @@ fn test_aio_suspend() {
}
}

assert!(wcb.aio_return().unwrap() as usize == WBUF.len());
assert!(rcb.aio_return().unwrap() as usize == rlen);
assert_eq!(wcb.aio_return().unwrap() as usize, WBUF.len());
assert_eq!(rcb.aio_return().unwrap() as usize, rlen);
}

// Test a simple aio operation with no completion notification. We must poll
// for completion
#[test]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
fn test_read() {
const INITIAL: &[u8] = b"abcdef123456";
let mut rbuf = vec![0; 4];
Expand All @@ -192,11 +186,11 @@ fn test_read() {
aiocb.read().unwrap();

let err = poll_aio(&mut aiocb);
assert!(err == Ok(()));
assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len());
assert_eq!(err, Ok(()));
assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len());
}

assert!(EXPECT == rbuf.deref().deref());
assert_eq!(EXPECT, &*rbuf);
}

/// `AioCb::read` should not modify the `AioCb` object if `libc::aio_read`
Expand All @@ -221,7 +215,6 @@ fn test_read_error() {

// Tests from_mut_slice
#[test]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
fn test_read_into_mut_slice() {
const INITIAL: &[u8] = b"abcdef123456";
let mut rbuf = vec![0; 4];
Expand All @@ -238,16 +231,15 @@ fn test_read_into_mut_slice() {
aiocb.read().unwrap();

let err = poll_aio(&mut aiocb);
assert!(err == Ok(()));
assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len());
assert_eq!(err, Ok(()));
assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len());
}

assert!(rbuf == EXPECT);
assert_eq!(rbuf, EXPECT);
}

// Tests from_ptr
#[test]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
fn test_read_into_pointer() {
const INITIAL: &[u8] = b"abcdef123456";
let mut rbuf = vec![0; 4];
Expand All @@ -268,18 +260,16 @@ fn test_read_into_pointer() {
aiocb.read().unwrap();

let err = poll_aio(&mut aiocb);
assert!(err == Ok(()));
assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len());
assert_eq!(err, Ok(()));
assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len());
}

assert!(rbuf == EXPECT);
assert_eq!(rbuf, EXPECT);
}

// Test reading into an immutable buffer. It should fail
// FIXME: This test fails to panic on Linux/musl
// Test reading into an immutable buffer. It should fail with a panic.
#[test]
#[should_panic(expected = "Can't read into an immutable buffer")]
#[cfg_attr(target_env = "musl", ignore)]
fn test_read_immutable_buffer() {
let rbuf: &[u8] = b"CDEF";
let f = tempfile().unwrap();
Expand All @@ -292,11 +282,9 @@ fn test_read_immutable_buffer() {
aiocb.read().unwrap();
}


// Test a simple aio operation with no completion notification. We must poll
// for completion. Unlike test_aio_read, this test uses AioCb::from_slice
#[test]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
fn test_write() {
const INITIAL: &[u8] = b"abcdef123456";
let wbuf = "CDEF".to_string().into_bytes();
Expand All @@ -314,18 +302,17 @@ fn test_write() {
aiocb.write().unwrap();

let err = poll_aio(&mut aiocb);
assert!(err == Ok(()));
assert!(aiocb.aio_return().unwrap() as usize == wbuf.len());
assert_eq!(err, Ok(()));
assert_eq!(aiocb.aio_return().unwrap() as usize, wbuf.len());

f.seek(SeekFrom::Start(0)).unwrap();
let len = f.read_to_end(&mut rbuf).unwrap();
assert!(len == EXPECT.len());
assert!(rbuf == EXPECT);
assert_eq!(len, EXPECT.len());
assert_eq!(rbuf, EXPECT);
}

// Tests `AioCb::from_boxed_slice` with `Bytes`
#[test]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
fn test_write_bytes() {
const INITIAL: &[u8] = b"abcdef123456";
let wbuf = Box::new(Bytes::from(&b"CDEF"[..]));
Expand All @@ -344,18 +331,17 @@ fn test_write_bytes() {
aiocb.write().unwrap();

let err = poll_aio(&mut aiocb);
assert!(err == Ok(()));
assert!(aiocb.aio_return().unwrap() as usize == expected_len);
assert_eq!(err, Ok(()));
assert_eq!(aiocb.aio_return().unwrap() as usize, expected_len);

f.seek(SeekFrom::Start(0)).unwrap();
let len = f.read_to_end(&mut rbuf).unwrap();
assert!(len == EXPECT.len());
assert!(rbuf == EXPECT);
assert_eq!(len, EXPECT.len());
assert_eq!(rbuf, EXPECT);
}

// Tests `AioCb::from_boxed_mut_slice` with `BytesMut`
#[test]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
fn test_read_bytes_mut_small() {
const INITIAL: &[u8] = b"abcdef";
let rbuf = Box::new(BytesMut::from(vec![0; 4]));
Expand All @@ -380,7 +366,6 @@ fn test_read_bytes_mut_small() {

// Tests `AioCb::from_ptr`
#[test]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
fn test_write_from_pointer() {
const INITIAL: &[u8] = b"abcdef123456";
let wbuf = "CDEF".to_string().into_bytes();
Expand All @@ -402,13 +387,13 @@ fn test_write_from_pointer() {
aiocb.write().unwrap();

let err = poll_aio(&mut aiocb);
assert!(err == Ok(()));
assert!(aiocb.aio_return().unwrap() as usize == wbuf.len());
assert_eq!(err, Ok(()));
assert_eq!(aiocb.aio_return().unwrap() as usize, wbuf.len());

f.seek(SeekFrom::Start(0)).unwrap();
let len = f.read_to_end(&mut rbuf).unwrap();
assert!(len == EXPECT.len());
assert!(rbuf == EXPECT);
assert_eq!(len, EXPECT.len());
assert_eq!(rbuf, EXPECT);
}

/// `AioCb::write` should not modify the `AioCb` object if `libc::aio_write`
Expand All @@ -433,20 +418,19 @@ lazy_static! {
}

extern fn sigfunc(_: c_int) {
SIGNALED.store(true, Ordering::Relaxed);
SIGNALED.store(true, Ordering::SeqCst);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Relaxed is fine here, because SIGNALED isn't being used to control access to any other variables. It's only being accessed by itself, so stricter atomic instructions aren't needed. This is the kind of application that, in C, wouldn't even use special instructions, just a sigatomic_t variable.

}

// Test an aio operation with completion delivered by a signal
// FIXME: This test is ignored on mips because of failures in qemu in CI
#[test]
#[cfg_attr(any(all(target_env = "musl", target_arch = "x86_64"), target_arch = "mips", target_arch = "mips64"), ignore)]
#[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)]
fn test_write_sigev_signal() {
#[allow(unused_variables)]
let m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
let sa = SigAction::new(SigHandler::Handler(sigfunc),
SaFlags::SA_RESETHAND,
SigSet::empty());
SIGNALED.store(false, Ordering::Relaxed);
SIGNALED.store(false, Ordering::SeqCst);
unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap();

const INITIAL: &[u8] = b"abcdef123456";
Expand All @@ -466,22 +450,21 @@ fn test_write_sigev_signal() {
},
LioOpcode::LIO_NOP);
aiocb.write().unwrap();
while !SIGNALED.load(Ordering::Relaxed) {
while !SIGNALED.load(Ordering::SeqCst) {
thread::sleep(time::Duration::from_millis(10));
}

assert!(aiocb.aio_return().unwrap() as usize == WBUF.len());
assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
f.seek(SeekFrom::Start(0)).unwrap();
let len = f.read_to_end(&mut rbuf).unwrap();
assert!(len == EXPECT.len());
assert!(rbuf == EXPECT);
assert_eq!(len, EXPECT.len());
assert_eq!(rbuf, EXPECT);
}

// Test LioCb::listio with LIO_WAIT, so all AIO ops should be complete by the
// time listio returns.
#[test]
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
fn test_liocb_listio_wait() {
const INITIAL: &[u8] = b"abcdef123456";
const WBUF: &[u8] = b"CDEF";
Expand Down Expand Up @@ -513,22 +496,21 @@ fn test_liocb_listio_wait() {
let err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone);
err.expect("lio_listio");

assert!(liocb.aio_return(0).unwrap() as usize == WBUF.len());
assert!(liocb.aio_return(1).unwrap() as usize == rlen);
assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len());
assert_eq!(liocb.aio_return(1).unwrap() as usize, rlen);
}
assert!(rbuf.deref().deref() == b"3456");
assert_eq!(rbuf, b"3456");

f.seek(SeekFrom::Start(0)).unwrap();
let len = f.read_to_end(&mut rbuf2).unwrap();
assert!(len == EXPECT.len());
assert!(rbuf2 == EXPECT);
assert_eq!(len, EXPECT.len());
assert_eq!(rbuf2, EXPECT);
}

// Test LioCb::listio with LIO_NOWAIT and no SigEvent, so we must use some other
// mechanism to check for the individual AioCb's completion.
#[test]
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
fn test_liocb_listio_nowait() {
const INITIAL: &[u8] = b"abcdef123456";
const WBUF: &[u8] = b"CDEF";
Expand Down Expand Up @@ -562,26 +544,25 @@ fn test_liocb_listio_nowait() {

poll_aio(&mut liocb.aiocbs[0]).unwrap();
poll_aio(&mut liocb.aiocbs[1]).unwrap();
assert!(liocb.aiocbs[0].aio_return().unwrap() as usize == WBUF.len());
assert!(liocb.aiocbs[1].aio_return().unwrap() as usize == rlen);
assert_eq!(liocb.aiocbs[0].aio_return().unwrap() as usize, WBUF.len());
assert_eq!(liocb.aiocbs[1].aio_return().unwrap() as usize, rlen);
}
assert!(rbuf.deref().deref() == b"3456");
assert_eq!(rbuf, b"3456");

f.seek(SeekFrom::Start(0)).unwrap();
let len = f.read_to_end(&mut rbuf2).unwrap();
assert!(len == EXPECT.len());
assert!(rbuf2 == EXPECT);
assert_eq!(len, EXPECT.len());
assert_eq!(rbuf2, EXPECT);
}

// Test LioCb::listio with LIO_NOWAIT and a SigEvent to indicate when all
// AioCb's are complete.
// FIXME: This test is ignored on mips/mips64 because of failures in qemu in CI.
#[test]
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
#[cfg_attr(any(target_arch = "mips", target_arch = "mips64", target_env = "musl"), ignore)]
#[cfg_attr(any(all(target_arch = "x86", target_env = "musl"), target_arch = "mips", target_arch = "mips64"), ignore)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this test fails on x86 with musl, why do you think it will work better on other architectures with musl?

fn test_liocb_listio_signal() {
#[allow(unused_variables)]
let m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
const INITIAL: &[u8] = b"abcdef123456";
const WBUF: &[u8] = b"CDEF";
let mut rbuf = vec![0; 4];
Expand Down Expand Up @@ -614,30 +595,30 @@ fn test_liocb_listio_signal() {
let mut liocb = LioCb::with_capacity(2);
liocb.aiocbs.push(wcb);
liocb.aiocbs.push(rcb);
SIGNALED.store(false, Ordering::Relaxed);
SIGNALED.store(false, Ordering::SeqCst);
unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap();
let err = liocb.listio(LioMode::LIO_NOWAIT, sigev_notify);
err.expect("lio_listio");
while !SIGNALED.load(Ordering::Relaxed) {
while !SIGNALED.load(Ordering::SeqCst) {
thread::sleep(time::Duration::from_millis(10));
}

assert!(liocb.aiocbs[0].aio_return().unwrap() as usize == WBUF.len());
assert!(liocb.aiocbs[1].aio_return().unwrap() as usize == rlen);
assert_eq!(liocb.aiocbs[0].aio_return().unwrap() as usize, WBUF.len());
assert_eq!(liocb.aiocbs[1].aio_return().unwrap() as usize, rlen);
}
assert!(rbuf.deref().deref() == b"3456");
assert_eq!(rbuf, b"3456");

f.seek(SeekFrom::Start(0)).unwrap();
let len = f.read_to_end(&mut rbuf2).unwrap();
assert!(len == EXPECT.len());
assert!(rbuf2 == EXPECT);
assert_eq!(len, EXPECT.len());
assert_eq!(rbuf2, EXPECT);
}

// Try to use LioCb::listio to read into an immutable buffer. It should fail
// FIXME: This test fails to panic on Linux/musl
#[test]
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
#[should_panic(expected = "Can't read into an immutable buffer")]
// FIXME: This test fails on Travis with "failed to initiate panic, error 5"
#[cfg_attr(target_env = "musl", ignore)]
fn test_liocb_listio_read_immutable() {
let rbuf: &[u8] = b"abcd";
Expand Down