我正在用Rust编写一个系统守护进程,用户可以手动启动它。一次只应该运行一个守护进程实例,因此我创建了一个pidfile锁定机制来防止多个实例。这是我第一次做任何类型的unix风格的文件锁定,我希望能有另一双眼睛来检查我可能错过的任何东西。
风格指针也将是伟大的,因为我是新的锈。
use nix::fcntl::{flock, FlockArg};
use nix::sys::signal::kill;
use nix::unistd::Pid;
use std::fs::File;
use std::fs::OpenOptions;
use std::io;
use std::io::{Error, ErrorKind, Read, Seek, SeekFrom, Write};
use std::os::unix::io::AsRawFd;
use std::path;
use std::process;
fn write_pid(mut file: &File) -> Result<(), io::Error> {
let id = process::id().to_string() + "\n";
file.write_all(id.as_bytes())?;
Ok(())
}
fn lock_pidfile(file: &File, pidfile: &path::Path) -> Result<(), io::Error> {
flock(file.as_raw_fd(), FlockArg::LockExclusiveNonblock).map_err(|_| {
Error::new(
ErrorKind::Other,
format!("Failed to lock pidfile: {}", pidfile.display()),
)
})
}
pub fn exclusive(pidfile: &path::Path) -> Result<bool, io::Error> {
let pf = OpenOptions::new()
.write(true)
.create_new(true)
.open(pidfile);
match pf {
Ok(file) => {
lock_pidfile(&file, pidfile)?;
write_pid(&file)?;
Ok(true)
}
Err(err) => {
match err.kind() {
ErrorKind::AlreadyExists => {
let mut file = OpenOptions::new().read(true).write(true).open(pidfile)?;
lock_pidfile(&file, pidfile)?;
let mut id_str = String::new();
file.read_to_string(&mut id_str)?;
let id: u32 = id_str.trim().parse().map_err(|_| {
Error::new(
ErrorKind::Other,
format!("Failed to parse pidfile: {}", pidfile.display()),
)
})?;
// Kill None just checks if process exists.
// Same as kill(pid, 0); in C
if kill(Pid::from_raw(id as i32), None).is_ok() {
Ok(false)
} else {
file.seek(SeekFrom::Start(0))?;
write_pid(&file)?;
Ok(true)
}
}
_ => Err(err),
}
}
}
}
```发布于 2019-05-24 05:30:36
我对文件锁定不太了解,但我可以在铁锈里指导你。
我建议您将write_pid更改为使用writeln!。我想你可以把它简化成这样。
fn write_pid(mut file: &File) -> Result<(), io::Error> {
writeln!(file, "{}", process::id())
}我还希望减少exclusive中的嵌套,可能如下所示:
pub fn exclusive(pidfile: &path::Path) -> Result<bool, io::Error> {
let pf = OpenOptions::new()
.write(true)
.create_new(true)
.open(pidfile);
match pf {
Ok(file) => {
lock_pidfile(&file, pidfile)?;
write_pid(&file)?;
return Ok(true);
}
Err(ref e) if e.kind() == ErrorKind::AlreadyExists => {}
Err(e) => return Err(e),
}
let mut file = OpenOptions::new().read(true).write(true).open(pidfile)?;
lock_pidfile(&file, pidfile)?;
let mut id_str = String::new();
file.read_to_string(&mut id_str)?;
let id: u32 = id_str.trim().parse().map_err(|_| {
Error::new(
ErrorKind::Other,
format!("Failed to parse pidfile: {}", pidfile.display()),
)
})?;
// Kill None just checks if process exists.
// Same as kill(pid, 0); in C
if kill(Pid::from_raw(id as i32), None).is_ok() {
Ok(false)
} else {
file.seek(SeekFrom::Start(0))?;
write_pid(&file)?;
Ok(true)
}
}https://codereview.stackexchange.com/questions/220825
复制相似问题