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-iocrate异步管理进程。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