1个不稳定版本
0.1.0 | 2024年7月3日 |
---|
#311 in Unix API
156 每月下载量
在 10 个crate中使用(通过swayipc-async)
18KB
174 行
这是async-pidfd
的维护分支。
Linux的进程文件描述符(pidfd
)
进程文件描述符(pidfd
)为Linux上的进程管理提供了一种无竞争的方法,通过文件描述符而不是进程ID(PID)来保持对进程的持续引用,进程退出后PID可能会被重用。
此crate仅适用于Linux;如果您需要其他平台的支持或旧版Linux内核的支持,请参阅async-process。
async-pidfd
为pidfd提供Rust支持,并支持同步(通过PidFd
类型)和异步(通过AsyncPidFd
类型)管理进程。
同步 - PidFd
PidFd
类型同步管理进程。使用PidFd::from_pid
从进程ID构建PidFd
,例如从标准库中的Child::id
。请注意,可移植的Child::id
函数返回进程ID为u32
,而不是libc::pid_t
,因此需要进行类型转换。
use std::os::unix::process::ExitStatusExt;
use std::process::{Command, ExitStatus};
use async_pidfd::PidFd;
fn main() -> std::io::Result<()> {
let child = Command::new("/bin/true").spawn()?;
let pidfd = PidFd::from_pid(child.id() as libc::pid_t)?;
let status = pidfd.wait()?.status();
assert_eq!(status.code(), Some(0));
let child = Command::new("/bin/sh").arg("-c").arg("kill -9 $$").spawn()?;
let pidfd = PidFd::from_pid(child.id() as libc::pid_t)?;
let status = pidfd.wait()?.status();
assert_eq!(status.signal(), Some(9));
Ok(())
}
PidFd::wait
通过 ExitInfo
结构体返回有关已退出进程的信息。 ExitInfo
包含一个 libc::siginfo_t
,指示进程如何退出(包括如果它正常退出,则包括退出代码,如果它被信号终止,则包括信号),以及一个 libc::rusage
,描述进程及其子进程的资源使用情况。 libc::siginfo_t
具有复杂的语义;要获取 std::process::ExitStatus
,您可以在 ExitInfo
上调用 .status()
。
请注意,虽然为任意进程打开 PID 可能会与该进程的退出发生竞争,但打开尚未等待的子进程的 PID 是安全的,因为进程 ID 会在您等待进程(或阻塞 SIGCHLD
)之前不会重用。
如果您只想使用同步的 PidFd
类型,您可以在 Cargo.toml
中使用 async-pidfd
与 default-features = false
来删除与异步相关的依赖项。
异步 - AsyncPidFd
AsyncPidFd
类型根据 Stjepan Glavina 的 async-io
crate 异步管理进程。 async-io
提供了一个 Async
包装器,它可以将任何基于文件描述符的同步类型轻松地转换为异步类型;生成的异步代码使用 epoll
并发地等待所有文件描述符。
AsyncPidFd
包装了一个 Async<PidFd>
并提供了与 PidFd::wait
相同的 API,但提供了异步版本的 wait
函数。
use std::os::unix::process::ExitStatusExt;
use std::process::{Command, ExitStatus};
use async_pidfd::AsyncPidFd;
use futures_lite::future;
async fn async_spawn_and_status(cmd: &mut Command) -> std::io::Result<ExitStatus> {
let child = cmd.spawn()?;
let pidfd = AsyncPidFd::from_pid(child.id() as libc::pid_t)?;
Ok(pidfd.wait().await?.status())
}
fn main() -> std::io::Result<()> {
future::block_on(async {
let (status1, status2) = future::try_join(
async_spawn_and_status(&mut Command::new("/bin/true")),
async_spawn_and_status(&mut Command::new("/bin/false")),
)
.await?;
assert_eq!(status1.code(), Some(0));
assert_eq!(status2.code(), Some(1));
Ok(())
})
}
依赖项
~0–8MB
~71K SLoC