5 个版本
0.1.4 | 2020 年 11 月 15 日 |
---|---|
0.1.3 | 2020 年 10 月 1 日 |
0.1.2 | 2020 年 8 月 20 日 |
0.1.1 | 2020 年 8 月 11 日 |
0.1.0 | 2020 年 8 月 11 日 |
#306 在 Unix API 中
4,454 每月下载量
用于 4 个 crate (3 个直接)
18KB
174 行
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
类型,你可以使用async-pidfd
与Cargo.toml中的
default-features = false
来删除与异步相关的依赖项。
异步 - AsyncPidFd
AsyncPidFd
类型基于Stjepan Glavina的async-io
crate异步管理进程。async-io
提供了一个Async
包装器,可以轻松地将任何基于文件描述符的同步类型转换为异步类型;生成的异步代码使用epoll
同时等待所有文件描述符。
AsyncPidFd
包装了一个Async<PidFd>
,并提供与PidFd
相同的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–12MB
~97K SLoC