I found that there is a problem with blocking the opening of fifo files in concurrency. If reading, writing, or deleting fifo files are performed concurrently while blocking read and write operations, there is a chance that the owner will get stuck when opening the Fifo file, especially on the write side. Because the file is deleted, the read side will never be able to access it, resulting in a situation of freezing. I tried golang to do this test and found that it still exists. Under the stack, openfile will always be stuck at
" wait_for_partner+0x19/0x50"
. I don't know if this is the mechanism of the kernel or what?(but also linux 6.X kernel) But can Rust avoid this situation?
use std::{path::PathBuf, fs::OpenOptions};
use nix::{unistd::mkfifo, sys::stat::Mode};
#[tokio::main]
async fn main() {
let fifo_path = "/tmp/";
let mut cnt = 1;
loop{
let std_in = PathBuf::from(fifo_path).join("stdin-fifo");
mkfifo(&std_in, Mode::S_IRWXU).unwrap_or_default();
let std_in2 = std_in.clone();
let std_in3 = std_in.clone();
let r2 = tokio::task::spawn(async move{
println!("open read fifo start");
std::fs::OpenOptions::new().read(true).open(&std_in2).map_err(|e| println!("err {:?}",e));
// tokio::fs::OpenOptions::new().read(true).open(&std_in2).await;
println!("open read fifo end");
});
let r3 = tokio::task::spawn(async move {
println!("remove fifo start");
std::fs::remove_file(&std_in3);
// tokio::fs::remove_file(&std_in3).await;
println!("remove fifo end");
});
let r1 = tokio::task::spawn(async move{
println!("open write fifo start");
std::fs::OpenOptions::new().create(true).write(true).open(&std_in).map_err(|e| print!("err {:?}",e));
// tokio::fs::OpenOptions::new().create(true).write(true).open(&std_in).await;
println!("open write fifo end");
});
r1.await;
r2.await;
r3.await;
println!("success {}",cnt);
cnt += 1;
}
}
2 posts - 1 participant