sys_util: Add ability to set the depth of a pipe

It will be useful to set the pipe depth in unit tests. The first use
will be to set the depth before filling the pipe so the pipe can be used
to test blocking writes.

Change-Id: Ia8c2b01f7f4b08bd59a0442c5e7bff02bf25c77c
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2345376
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
Dylan Reid 2020-08-09 05:45:52 -07:00 committed by Commit Bot
parent e0b29ad24d
commit 1330619561

View file

@ -291,6 +291,35 @@ pub fn pipe(close_on_exec: bool) -> Result<(File, File)> {
} }
} }
/// Sets the pipe signified with fd to `size`.
///
/// Returns the new size of the pipe or an error if the OS fails to set the pipe size.
pub fn set_pipe_size(fd: RawFd, size: usize) -> Result<usize> {
// Safe because fcntl with the `F_SETPIPE_SZ` arg doesn't touch memory.
let ret = unsafe { fcntl(fd, libc::F_SETPIPE_SZ, size as c_int) };
if ret < 0 {
return errno_result();
}
Ok(ret as usize)
}
/// Test-only function used to create a pipe that is full. The pipe is created, has its size set to
/// the minimum and then has that much data written to it. Use `new_pipe_full` to test handling of
/// blocking `write` calls in unit tests.
pub fn new_pipe_full() -> Result<(File, File)> {
use std::io::Write;
let (rx, mut tx) = pipe(true)?;
// The smallest allowed size of a pipe is the system page size on linux.
let page_size = set_pipe_size(tx.as_raw_fd(), round_up_to_page_size(1))?;
// Fill the pipe with page_size zeros so the next write call will block.
let buf = vec![0u8; page_size];
tx.write_all(&buf)?;
Ok((rx, tx))
}
/// Used to attempt to clean up a named pipe after it is no longer used. /// Used to attempt to clean up a named pipe after it is no longer used.
pub struct UnlinkUnixDatagram(pub UnixDatagram); pub struct UnlinkUnixDatagram(pub UnixDatagram);
impl AsRef<UnixDatagram> for UnlinkUnixDatagram { impl AsRef<UnixDatagram> for UnlinkUnixDatagram {
@ -393,3 +422,21 @@ pub fn clear_fd_flags(fd: RawFd, clear_flags: c_int) -> Result<()> {
let start_flags = get_fd_flags(fd)?; let start_flags = get_fd_flags(fd)?;
set_fd_flags(fd, start_flags & !clear_flags) set_fd_flags(fd, start_flags & !clear_flags)
} }
#[cfg(test)]
mod tests {
use std::io::Write;
use super::*;
#[test]
fn pipe_size_and_fill() {
let (_rx, mut tx) = new_pipe_full().expect("Failed to pipe");
// To check that setting the size worked, set the descriptor to non blocking and check that
// write returns an error.
add_fd_flags(tx.as_raw_fd(), libc::O_NONBLOCK).expect("Failed to set tx non blocking");
tx.write(&[0u8; 8])
.expect_err("Write after fill didn't fail");
}
}