Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 619fd96

Browse files
committed
Add PidFd type and seal traits
Improve docs Split do_fork into two Make do_fork unsafe Add target attribute to create_pidfd field in Command Add method to get create_pidfd value
1 parent ef03de2 commit 619fd96

File tree

4 files changed

+282
-113
lines changed

4 files changed

+282
-113
lines changed

library/std/src/os/linux/process.rs

Lines changed: 124 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,142 @@
22
33
#![unstable(feature = "linux_pidfd", issue = "none")]
44

5-
use crate::process;
6-
use crate::sys_common::AsInnerMut;
75
use crate::io::Result;
6+
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
7+
use crate::process;
8+
use crate::sys::fd::FileDesc;
9+
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
810

9-
/// Os-specific extensions to [`process::Child`]
11+
/// This type represents a file descriptor that refers to a process.
12+
///
13+
/// A `PidFd` can be obtained by setting the corresponding option on [`Command`]
14+
/// with [`create_pidfd`]. Subsequently, the created pidfd can be retrieved
15+
/// from the [`Child`] by calling [`pidfd`] or [`take_pidfd`].
16+
///
17+
/// Example:
18+
/// ```no_run
19+
/// #![feature(linux_pidfd)]
20+
/// use std::os::linux::process::{CommandExt, ChildExt};
21+
/// use std::process::Command;
22+
///
23+
/// let mut child = Command::new("echo")
24+
/// .create_pidfd(true)
25+
/// .spawn()
26+
/// .expect("Failed to spawn child");
1027
///
11-
/// [`process::Child`]: crate::process::Child
12-
pub trait ChildExt {
13-
/// Obtains the pidfd created for this child process, if available.
28+
/// let pidfd = child
29+
/// .take_pidfd()
30+
/// .expect("Failed to retrieve pidfd");
31+
///
32+
/// // The file descriptor will be closed when `pidfd` is dropped.
33+
/// ```
34+
/// Refer to the man page of `pidfd_open(2)` for further details.
35+
///
36+
/// [`Command`]: process::Command
37+
/// [`create_pidfd`]: CommandExt::create_pidfd
38+
/// [`Child`]: process::Child
39+
/// [`pidfd`]: fn@ChildExt::pidfd
40+
/// [`take_pidfd`]: ChildExt::take_pidfd
41+
#[derive(Debug)]
42+
pub struct PidFd {
43+
inner: FileDesc,
44+
}
45+
46+
impl AsInner<FileDesc> for PidFd {
47+
fn as_inner(&self) -> &FileDesc {
48+
&self.inner
49+
}
50+
}
51+
52+
impl FromInner<FileDesc> for PidFd {
53+
fn from_inner(inner: FileDesc) -> PidFd {
54+
PidFd { inner }
55+
}
56+
}
57+
58+
impl IntoInner<FileDesc> for PidFd {
59+
fn into_inner(self) -> FileDesc {
60+
self.inner
61+
}
62+
}
63+
64+
impl AsRawFd for PidFd {
65+
fn as_raw_fd(&self) -> RawFd {
66+
self.as_inner().raw()
67+
}
68+
}
69+
70+
impl FromRawFd for PidFd {
71+
unsafe fn from_raw_fd(fd: RawFd) -> Self {
72+
Self::from_inner(FileDesc::new(fd))
73+
}
74+
}
75+
76+
impl IntoRawFd for PidFd {
77+
fn into_raw_fd(self) -> RawFd {
78+
self.into_inner().into_raw()
79+
}
80+
}
81+
82+
mod private_child_ext {
83+
pub trait Sealed {}
84+
impl Sealed for crate::process::Child {}
85+
}
86+
87+
/// Os-specific extensions for [`Child`]
88+
///
89+
/// [`Child`]: process::Child
90+
pub trait ChildExt: private_child_ext::Sealed {
91+
/// Obtains a reference to the [`PidFd`] created for this [`Child`], if available.
92+
///
93+
/// A pidfd will only be available if its creation was requested with
94+
/// [`create_pidfd`] when the corresponding [`Command`] was created.
1495
///
15-
/// A pidfd will only ever be available if `create_pidfd(true)` was called
16-
/// when the corresponding `Command` was created.
96+
/// Even if requested, a pidfd may not be available due to an older
97+
/// version of Linux being in use, or if some other error occurred.
98+
///
99+
/// [`Command`]: process::Command
100+
/// [`create_pidfd`]: CommandExt::create_pidfd
101+
/// [`Child`]: process::Child
102+
fn pidfd(&self) -> Result<&PidFd>;
103+
104+
/// Takes ownership of the [`PidFd`] created for this [`Child`], if available.
17105
///
18-
/// Even if `create_pidfd(true)` is called, a pidfd may not be available
19-
/// due to an older version of Linux being in use, or if
20-
/// some other error occured.
106+
/// A pidfd will only be available if its creation was requested with
107+
/// [`create_pidfd`] when the corresponding [`Command`] was created.
21108
///
22-
/// See `man pidfd_open` for more details about pidfds.
23-
fn pidfd(&self) -> Result<i32>;
109+
/// Even if requested, a pidfd may not be available due to an older
110+
/// version of Linux being in use, or if some other error occurred.
111+
///
112+
/// [`Command`]: process::Command
113+
/// [`create_pidfd`]: CommandExt::create_pidfd
114+
/// [`Child`]: process::Child
115+
fn take_pidfd(&mut self) -> Result<PidFd>;
116+
}
117+
118+
mod private_command_ext {
119+
pub trait Sealed {}
120+
impl Sealed for crate::process::Command {}
24121
}
25122

26-
/// Os-specific extensions to [`process::Command`]
123+
/// Os-specific extensions for [`Command`]
27124
///
28-
/// [`process::Command`]: crate::process::Command
29-
pub trait CommandExt {
30-
/// Sets whether or this `Command` will attempt to create a pidfd
31-
/// for the child. If this method is never called, a pidfd will
32-
/// not be crated.
125+
/// [`Command`]: process::Command
126+
pub trait CommandExt: private_command_ext::Sealed {
127+
/// Sets whether a [`PidFd`](struct@PidFd) should be created for the [`Child`]
128+
/// spawned by this [`Command`].
129+
/// By default, no pidfd will be created.
33130
///
34-
/// The pidfd can be retrieved from the child via [`ChildExt::pidfd`]
131+
/// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd`].
35132
///
36133
/// A pidfd will only be created if it is possible to do so
37-
/// in a guaranteed race-free manner (e.g. if the `clone3` system call is
38-
/// supported). Otherwise, [`ChildExit::pidfd`] will return an error.
134+
/// in a guaranteed race-free manner (e.g. if the `clone3` system call
135+
/// is supported). Otherwise, [`pidfd`] will return an error.
136+
///
137+
/// [`Command`]: process::Command
138+
/// [`Child`]: process::Child
139+
/// [`pidfd`]: fn@ChildExt::pidfd
140+
/// [`take_pidfd`]: ChildExt::take_pidfd
39141
fn create_pidfd(&mut self, val: bool) -> &mut process::Command;
40142
}
41143

library/std/src/sys/unix/process/process_common.rs

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ pub struct Command {
7979
stdin: Option<Stdio>,
8080
stdout: Option<Stdio>,
8181
stderr: Option<Stdio>,
82-
pub(crate) make_pidfd: bool,
82+
#[cfg(target_os = "linux")]
83+
create_pidfd: bool,
8384
}
8485

8586
// Create a new type for argv, so that we can make it `Send` and `Sync`
@@ -125,6 +126,7 @@ pub enum Stdio {
125126
}
126127

127128
impl Command {
129+
#[cfg(not(target_os = "linux"))]
128130
pub fn new(program: &OsStr) -> Command {
129131
let mut saw_nul = false;
130132
let program = os2c(program, &mut saw_nul);
@@ -142,7 +144,28 @@ impl Command {
142144
stdin: None,
143145
stdout: None,
144146
stderr: None,
145-
make_pidfd: false,
147+
}
148+
}
149+
150+
#[cfg(target_os = "linux")]
151+
pub fn new(program: &OsStr) -> Command {
152+
let mut saw_nul = false;
153+
let program = os2c(program, &mut saw_nul);
154+
Command {
155+
argv: Argv(vec![program.as_ptr(), ptr::null()]),
156+
args: vec![program.clone()],
157+
program,
158+
env: Default::default(),
159+
cwd: None,
160+
uid: None,
161+
gid: None,
162+
saw_nul,
163+
closures: Vec::new(),
164+
groups: None,
165+
stdin: None,
166+
stdout: None,
167+
stderr: None,
168+
create_pidfd: false,
146169
}
147170
}
148171

@@ -178,9 +201,21 @@ impl Command {
178201
pub fn groups(&mut self, groups: &[gid_t]) {
179202
self.groups = Some(Box::from(groups));
180203
}
181-
204+
205+
#[cfg(target_os = "linux")]
182206
pub fn create_pidfd(&mut self, val: bool) {
183-
self.make_pidfd = val;
207+
self.create_pidfd = val;
208+
}
209+
210+
#[cfg(not(target_os = "linux"))]
211+
#[allow(dead_code)]
212+
pub fn get_create_pidfd(&self) -> bool {
213+
false
214+
}
215+
216+
#[cfg(target_os = "linux")]
217+
pub fn get_create_pidfd(&self) -> bool {
218+
self.create_pidfd
184219
}
185220

186221
pub fn saw_nul(&self) -> bool {

0 commit comments

Comments
 (0)