use alloc::sync::Arc;
use core::{
future::{Future, poll_fn},
pin::pin,
task::Poll,
};
use ax_fs_ng::{BlockDeviceHandle, BlockError};
use rdif_block::CompletedRequest;
async fn read_one(
device: Arc<BlockDeviceHandle>,
lba: u64,
) -> Result<CompletedRequest, BlockError> {
let mut yielded = false;
poll_fn(|cx| {
if yielded {
Poll::Ready(())
} else {
yielded = true;
cx.waker().wake_by_ref();
Poll::Pending
}
})
.await;
device.axtest_read(lba).await
}
#[axtest::axtest]
fn block_runtime_async_double_read() {
let devices = BlockDeviceHandle::axtest_devices()
.expect("block runtime must be installed for block axtest");
let device = devices
.first()
.cloned()
.expect("block axtest requires an installed block device");
let info = device.device_info();
assert!(
info.num_blocks >= 2,
"block axtest requires at least two blocks"
);
let block_size = info.logical_block_size;
let mut first = pin!(read_one(Arc::clone(&device), 0));
let mut second = pin!(read_one(device, 1));
let mut first_result = None;
let mut second_result = None;
let mut first_pending_before_second = false;
let (first_result, second_result) = crate::task::future::block_on(poll_fn(|cx| {
let first_pending = if first_result.is_none() {
match first.as_mut().poll(cx) {
Poll::Ready(result) => {
first_result = Some(result);
false
}
Poll::Pending => true,
}
} else {
false
};
let second_polled = if second_result.is_none() {
match second.as_mut().poll(cx) {
Poll::Ready(result) => {
second_result = Some(result);
true
}
Poll::Pending => true,
}
} else {
false
};
if first_pending && second_polled {
first_pending_before_second = true;
}
match (first_result.take(), second_result.take()) {
(Some(first), Some(second)) => Poll::Ready((first, second)),
(first, second) => {
first_result = first;
second_result = second;
Poll::Pending
}
}
}));
assert!(
first_pending_before_second,
"second request was not polled while the first completion was pending"
);
let first = first_result.expect("first block request result");
let mut second = second_result.expect("second block request result");
second.id = first.id;
assert_eq!(first.result, Ok(()));
assert_eq!(second.result, Ok(()));
assert_eq!(
first.data.as_ref().map(|dma| dma.len().get()),
Some(block_size)
);
assert_eq!(
second.data.as_ref().map(|dma| dma.len().get()),
Some(block_size)
);
let mut first_data = first.data.expect("first completed DMA").into_cpu_buffer();
let second_data = second.data.expect("second completed DMA").into_cpu_buffer();
let second_bytes = second_data.as_slice_cpu().to_vec();
let mut replacement = second_bytes.clone();
replacement[0] ^= u8::MAX;
first_data.copy_from_slice_cpu(&replacement);
assert_eq!(first_data.as_slice_cpu(), replacement);
assert_eq!(second_data.as_slice_cpu(), second_bytes);
}