Move pipe ktests into `pipe::common`

This commit is contained in:
Wang Siyuan 2026-01-05 02:13:14 +00:00 committed by Tate, Hongliang Tian
parent b25e41dd4f
commit 8eade9b631
2 changed files with 157 additions and 143 deletions

View File

@ -234,146 +234,3 @@ impl Inode for AnonPipeInode {
fn set_ctime(&self, time: Duration);
fn fs(&self) -> Arc<dyn FileSystem>;
}
#[cfg(ktest)]
mod test {
use alloc::sync::Arc;
use core::sync::atomic::{self, AtomicBool};
use ostd::prelude::*;
use super::*;
use crate::thread::{Thread, kernel_thread::ThreadOptions};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Ordering {
WriteThenRead,
ReadThenWrite,
}
fn test_blocking<W, R>(write: W, read: R, ordering: Ordering)
where
W: FnOnce(Arc<AnonPipeFile>) + Send + 'static,
R: FnOnce(Arc<AnonPipeFile>) + Send + 'static,
{
let (reader, writer) = new_file_pair().unwrap();
let signal_writer = Arc::new(AtomicBool::new(false));
let signal_reader = signal_writer.clone();
let writer = ThreadOptions::new(move || {
if ordering == Ordering::ReadThenWrite {
while !signal_writer.load(atomic::Ordering::Relaxed) {
Thread::yield_now();
}
} else {
signal_writer.store(true, atomic::Ordering::Relaxed);
}
write(writer);
})
.spawn();
let reader = ThreadOptions::new(move || {
if ordering == Ordering::WriteThenRead {
while !signal_reader.load(atomic::Ordering::Relaxed) {
Thread::yield_now();
}
} else {
signal_reader.store(true, atomic::Ordering::Relaxed);
}
read(reader);
})
.spawn();
writer.join();
reader.join();
}
#[ktest]
fn test_read_empty() {
test_blocking(
|writer| {
assert_eq!(writer.write(&mut reader_from(&[1])).unwrap(), 1);
},
|reader| {
let mut buf = [0; 1];
assert_eq!(reader.read(&mut writer_from(&mut buf)).unwrap(), 1);
assert_eq!(&buf, &[1]);
},
Ordering::ReadThenWrite,
);
}
#[ktest]
fn test_write_full() {
test_blocking(
|writer| {
assert_eq!(writer.write(&mut reader_from(&[1, 2, 3])).unwrap(), 2);
assert_eq!(writer.write(&mut reader_from(&[2])).unwrap(), 1);
},
|reader| {
let mut buf = [0; 3];
assert_eq!(reader.read(&mut writer_from(&mut buf)).unwrap(), 2);
assert_eq!(&buf[..2], &[1, 2]);
assert_eq!(reader.read(&mut writer_from(&mut buf)).unwrap(), 1);
assert_eq!(&buf[..1], &[2]);
},
Ordering::WriteThenRead,
);
}
#[ktest]
fn test_read_closed() {
test_blocking(
drop,
|reader| {
let mut buf = [0; 1];
assert_eq!(reader.read(&mut writer_from(&mut buf)).unwrap(), 0);
},
Ordering::ReadThenWrite,
);
}
#[ktest]
fn test_write_closed() {
test_blocking(
|writer| {
assert_eq!(writer.write(&mut reader_from(&[1, 2, 3])).unwrap(), 2);
assert_eq!(
writer.write(&mut reader_from(&[2])).unwrap_err().error(),
Errno::EPIPE
);
},
drop,
Ordering::WriteThenRead,
);
}
#[ktest]
fn test_write_atomicity() {
test_blocking(
|writer| {
assert_eq!(writer.write(&mut reader_from(&[1])).unwrap(), 1);
assert_eq!(writer.write(&mut reader_from(&[1, 2])).unwrap(), 2);
},
|reader| {
let mut buf = [0; 3];
assert_eq!(reader.read(&mut writer_from(&mut buf)).unwrap(), 1);
assert_eq!(&buf[..1], &[1]);
assert_eq!(reader.read(&mut writer_from(&mut buf)).unwrap(), 2);
assert_eq!(&buf[..2], &[1, 2]);
},
Ordering::WriteThenRead,
);
}
fn reader_from(buf: &[u8]) -> VmReader<'_> {
VmReader::from(buf).to_fallible()
}
fn writer_from(buf: &mut [u8]) -> VmWriter<'_> {
VmWriter::from(buf).to_fallible()
}
}

View File

@ -459,3 +459,160 @@ impl Pollable for PipeWriter {
.poll_with(mask, poller, || self.check_io_events())
}
}
#[cfg(ktest)]
mod test {
use alloc::sync::Arc;
use core::sync::atomic::{self, AtomicBool};
use ostd::prelude::*;
use super::*;
use crate::thread::{Thread, kernel_thread::ThreadOptions};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Ordering {
WriteThenRead,
ReadThenWrite,
}
fn test_blocking<W, R>(write: W, read: R, ordering: Ordering)
where
W: FnOnce(Box<dyn FileIo>) + Send + 'static,
R: FnOnce(Box<dyn FileIo>) + Send + 'static,
{
let pipe = Pipe::new();
let reader = pipe
.open_anon(AccessMode::O_RDONLY, StatusFlags::empty())
.unwrap();
let writer = pipe
.open_anon(AccessMode::O_WRONLY, StatusFlags::empty())
.unwrap();
let signal_writer = Arc::new(AtomicBool::new(false));
let signal_reader = signal_writer.clone();
let writer = ThreadOptions::new(move || {
if ordering == Ordering::ReadThenWrite {
while !signal_writer.load(atomic::Ordering::Relaxed) {
Thread::yield_now();
}
} else {
signal_writer.store(true, atomic::Ordering::Relaxed);
}
write(writer);
})
.spawn();
let reader = ThreadOptions::new(move || {
if ordering == Ordering::WriteThenRead {
while !signal_reader.load(atomic::Ordering::Relaxed) {
Thread::yield_now();
}
} else {
signal_reader.store(true, atomic::Ordering::Relaxed);
}
read(reader);
})
.spawn();
writer.join();
reader.join();
}
#[ktest]
fn test_read_empty() {
test_blocking(
|writer| {
assert_eq!(write(writer.as_ref(), &[1]).unwrap(), 1);
},
|reader| {
let mut buf = [0; 1];
assert_eq!(read(reader.as_ref(), &mut buf).unwrap(), 1);
assert_eq!(&buf, &[1]);
},
Ordering::ReadThenWrite,
);
}
#[ktest]
fn test_write_full() {
test_blocking(
|writer| {
assert_eq!(write(writer.as_ref(), &[1, 2, 3]).unwrap(), 2);
assert_eq!(write(writer.as_ref(), &[2]).unwrap(), 1);
},
|reader| {
let mut buf = [0; 3];
assert_eq!(read(reader.as_ref(), &mut buf).unwrap(), 2);
assert_eq!(&buf[..2], &[1, 2]);
assert_eq!(read(reader.as_ref(), &mut buf).unwrap(), 1);
assert_eq!(&buf[..1], &[2]);
},
Ordering::WriteThenRead,
);
}
#[ktest]
fn test_read_closed() {
test_blocking(
drop,
|reader| {
let mut buf = [0; 1];
assert_eq!(read(reader.as_ref(), &mut buf).unwrap(), 0);
},
Ordering::ReadThenWrite,
);
}
#[ktest]
fn test_write_closed() {
test_blocking(
|writer| {
assert_eq!(write(writer.as_ref(), &[1, 2, 3]).unwrap(), 2);
assert_eq!(
write(writer.as_ref(), &[2]).unwrap_err().error(),
Errno::EPIPE
);
},
drop,
Ordering::WriteThenRead,
);
}
#[ktest]
fn test_write_atomicity() {
test_blocking(
|writer| {
assert_eq!(write(writer.as_ref(), &[1]).unwrap(), 1);
assert_eq!(write(writer.as_ref(), &[1, 2]).unwrap(), 2);
},
|reader| {
let mut buf = [0; 3];
assert_eq!(read(reader.as_ref(), &mut buf).unwrap(), 1);
assert_eq!(&buf[..1], &[1]);
assert_eq!(read(reader.as_ref(), &mut buf).unwrap(), 2);
assert_eq!(&buf[..2], &[1, 2]);
},
Ordering::WriteThenRead,
);
}
fn read(reader: &dyn FileIo, buf: &mut [u8]) -> crate::prelude::Result<usize> {
reader.read_at(
0,
&mut VmWriter::from(buf).to_fallible(),
StatusFlags::empty(),
)
}
fn write(writer: &dyn FileIo, buf: &[u8]) -> crate::prelude::Result<usize> {
writer.write_at(
0,
&mut VmReader::from(buf).to_fallible(),
StatusFlags::empty(),
)
}
}