Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0787c73

Browse files
committed
Add PidFd::{kill, wait, try_wait}
1 parent894f7a4 commit0787c73

File tree

7 files changed

+251
-117
lines changed

7 files changed

+251
-117
lines changed

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

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66

77
usecrate::io::Result;
88
usecrate::os::unix::io::{AsFd,AsRawFd,BorrowedFd,FromRawFd,IntoRawFd,OwnedFd,RawFd};
9-
usecrate::process;
9+
usecrate::process::{self,ExitStatus};
1010
usecrate::sealed::Sealed;
1111
#[cfg(not(doc))]
12-
usecrate::sys::fd::FileDesc;
12+
usecrate::sys::{fd::FileDesc, linux::pidfd::PidFdasInnerPidFd};
1313
usecrate::sys_common::{AsInner,AsInnerMut,FromInner,IntoInner};
1414

1515
#[cfg(doc)]
16-
structFileDesc;
16+
structInnerPidFd;
1717

1818
/// This type represents a file descriptor that refers to a process.
1919
///
@@ -47,63 +47,98 @@ struct FileDesc;
4747
/// [`take_pidfd`]: ChildExt::take_pidfd
4848
/// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html
4949
#[derive(Debug)]
50+
#[repr(transparent)]
5051
pubstructPidFd{
51-
inner:FileDesc,
52+
inner:InnerPidFd,
5253
}
5354

54-
implAsInner<FileDesc>forPidFd{
55+
implPidFd{
56+
/// Forces the child process to exit.
57+
///
58+
/// Unlike [`Child::kill`] it is possible to attempt to kill
59+
/// reaped children since PidFd does not suffer from pid recycling
60+
/// races. But doing so will return an Error.
61+
///
62+
/// [`Child::kill`]: process::Child::kill
63+
pubfnkill(&self) ->Result<()>{
64+
self.inner.kill()
65+
}
66+
67+
/// Waits for the child to exit completely, returning the status that it exited with.
68+
///
69+
/// Unlike [`Child::wait`] it does not ensure that the stdin handle is closed.
70+
/// Additionally it will not return an `ExitStatus` if the child
71+
/// has already been reaped. Instead an error will be returned.
72+
///
73+
/// [`Child::wait`]: process::Child::wait
74+
pubfnwait(&self) ->Result<ExitStatus>{
75+
self.inner.wait().map(FromInner::from_inner)
76+
}
77+
78+
/// Attempts to collect the exit status of the child if it has already exited.
79+
///
80+
/// Unlike [`Child::try_wait`] this method will return an Error
81+
/// if the child has already been reaped.
82+
///
83+
/// [`Child::try_wait`]: process::Child::try_wait
84+
pubfntry_wait(&self) ->Result<Option<ExitStatus>>{
85+
Ok(self.inner.try_wait()?.map(FromInner::from_inner))
86+
}
87+
}
88+
89+
implAsInner<InnerPidFd>forPidFd{
5590
#[inline]
56-
fnas_inner(&self) ->&FileDesc{
91+
fnas_inner(&self) ->&InnerPidFd{
5792
&self.inner
5893
}
5994
}
6095

61-
implFromInner<FileDesc>forPidFd{
62-
fnfrom_inner(inner:FileDesc) ->PidFd{
96+
implFromInner<InnerPidFd>forPidFd{
97+
fnfrom_inner(inner:InnerPidFd) ->PidFd{
6398
PidFd{ inner}
6499
}
65100
}
66101

67-
implIntoInner<FileDesc>forPidFd{
68-
fninto_inner(self) ->FileDesc{
102+
implIntoInner<InnerPidFd>forPidFd{
103+
fninto_inner(self) ->InnerPidFd{
69104
self.inner
70105
}
71106
}
72107

73108
implAsRawFdforPidFd{
74109
#[inline]
75110
fnas_raw_fd(&self) ->RawFd{
76-
self.as_inner().as_raw_fd()
111+
self.as_inner().as_inner().as_raw_fd()
77112
}
78113
}
79114

80115
implFromRawFdforPidFd{
81116
unsafefnfrom_raw_fd(fd:RawFd) ->Self{
82-
Self::from_inner(FileDesc::from_raw_fd(fd))
117+
Self::from_inner(InnerPidFd::from_raw_fd(fd))
83118
}
84119
}
85120

86121
implIntoRawFdforPidFd{
87122
fninto_raw_fd(self) ->RawFd{
88-
self.into_inner().into_raw_fd()
123+
self.into_inner().into_inner().into_raw_fd()
89124
}
90125
}
91126

92127
implAsFdforPidFd{
93128
fnas_fd(&self) ->BorrowedFd<'_>{
94-
self.as_inner().as_fd()
129+
self.as_inner().as_inner().as_fd()
95130
}
96131
}
97132

98133
implFrom<OwnedFd>forPidFd{
99134
fnfrom(fd:OwnedFd) ->Self{
100-
Self::from_inner(FileDesc::from_inner(fd))
135+
Self::from_inner(InnerPidFd::from_inner(FileDesc::from_inner(fd)))
101136
}
102137
}
103138

104139
implFrom<PidFd>forOwnedFd{
105140
fnfrom(pid_fd:PidFd) ->Self{
106-
pid_fd.into_inner().into_inner()
141+
pid_fd.into_inner().into_inner().into_inner()
107142
}
108143
}
109144

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pubmod pidfd;
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
usecrate::io;
2+
usecrate::os::fd::{AsRawFd,FromRawFd,RawFd};
3+
usecrate::sys::cvt;
4+
usecrate::sys::pal::unix::fd::FileDesc;
5+
usecrate::sys::process::ExitStatus;
6+
usecrate::sys_common::{AsInner,FromInner,IntoInner};
7+
8+
#[cfg(test)]
9+
mod tests;
10+
11+
#[derive(Debug)]
12+
pub(crate)structPidFd(FileDesc);
13+
14+
implPidFd{
15+
pubfnkill(&self) -> io::Result<()>{
16+
returncvt(unsafe{
17+
libc::syscall(
18+
libc::SYS_pidfd_send_signal,
19+
self.0.as_raw_fd(),
20+
libc::SIGKILL,
21+
crate::ptr::null::<()>(),
22+
0,
23+
)
24+
})
25+
.map(drop);
26+
}
27+
28+
pubfnwait(&self) -> io::Result<ExitStatus>{
29+
letmut siginfo: libc::siginfo_t =unsafe{crate::mem::zeroed()};
30+
cvt(unsafe{
31+
libc::waitid(libc::P_PIDFD,self.0.as_raw_fd()asu32,&mut siginfo, libc::WEXITED)
32+
})?;
33+
returnOk(ExitStatus::from_waitid_siginfo(siginfo));
34+
}
35+
36+
pubfntry_wait(&self) -> io::Result<Option<ExitStatus>>{
37+
letmut siginfo: libc::siginfo_t =unsafe{crate::mem::zeroed()};
38+
39+
cvt(unsafe{
40+
libc::waitid(
41+
libc::P_PIDFD,
42+
self.0.as_raw_fd()asu32,
43+
&mut siginfo,
44+
libc::WEXITED | libc::WNOHANG,
45+
)
46+
})?;
47+
ifunsafe{ siginfo.si_pid()} ==0{
48+
returnOk(None);
49+
}
50+
returnOk(Some(ExitStatus::from_waitid_siginfo(siginfo)));
51+
}
52+
}
53+
54+
implAsInner<FileDesc>forPidFd{
55+
fnas_inner(&self) ->&FileDesc{
56+
&self.0
57+
}
58+
}
59+
60+
implIntoInner<FileDesc>forPidFd{
61+
fninto_inner(self) ->FileDesc{
62+
self.0
63+
}
64+
}
65+
66+
implFromInner<FileDesc>forPidFd{
67+
fnfrom_inner(inner:FileDesc) ->Self{
68+
Self(inner)
69+
}
70+
}
71+
72+
implFromRawFdforPidFd{
73+
unsafefnfrom_raw_fd(fd:RawFd) ->Self{
74+
Self(FileDesc::from_raw_fd(fd))
75+
}
76+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
usecrate::assert_matches::assert_matches;
2+
usecrate::os::fd::{AsRawFd,RawFd};
3+
usecrate::os::linux::process::{ChildExt,CommandExt};
4+
usecrate::os::unix::process::ExitStatusExt;
5+
usecrate::process::Command;
6+
7+
#[test]
8+
fntest_command_pidfd(){
9+
let pidfd_open_available =probe_pidfd_support();
10+
11+
// always exercise creation attempts
12+
letmut child =Command::new("false").create_pidfd(true).spawn().unwrap();
13+
14+
// but only check if we know that the kernel supports pidfds.
15+
// We don't assert the precise value, since the standard library
16+
// might have opened other file descriptors before our code runs.
17+
if pidfd_open_available{
18+
assert!(child.pidfd().is_ok());
19+
}
20+
ifletOk(pidfd) = child.pidfd(){
21+
let flags =super::cvt(unsafe{ libc::fcntl(pidfd.as_raw_fd(), libc::F_GETFD)}).unwrap();
22+
assert!(flags& libc::FD_CLOEXEC !=0);
23+
}
24+
let status = child.wait().expect("error waiting on pidfd");
25+
assert_eq!(status.code(),Some(1));
26+
27+
letmut child =Command::new("sleep").arg("1000").create_pidfd(true).spawn().unwrap();
28+
assert_matches!(child.try_wait(),Ok(None));
29+
child.kill().expect("failed to kill child");
30+
let status = child.wait().expect("error waiting on pidfd");
31+
assert_eq!(status.signal(),Some(libc::SIGKILL));
32+
33+
let _ =Command::new("echo")
34+
.create_pidfd(false)
35+
.spawn()
36+
.unwrap()
37+
.pidfd()
38+
.expect_err("pidfd should not have been created when create_pid(false) is set");
39+
40+
let _ =Command::new("echo")
41+
.spawn()
42+
.unwrap()
43+
.pidfd()
44+
.expect_err("pidfd should not have been created");
45+
}
46+
47+
#[test]
48+
fntest_pidfd(){
49+
if !probe_pidfd_support(){
50+
return;
51+
}
52+
53+
letmut child =Command::new("sleep")
54+
.arg("1000")
55+
.create_pidfd(true)
56+
.spawn()
57+
.expect("executing 'sleep' failed");
58+
59+
let fd = child.take_pidfd().unwrap();
60+
drop(child);
61+
62+
assert_matches!(fd.try_wait(),Ok(None));
63+
fd.kill().expect("kill failed");
64+
fd.kill().expect("sending kill twice failed");
65+
let status = fd.wait().expect("1st wait failed");
66+
assert_eq!(status.signal(),Some(libc::SIGKILL));
67+
68+
// Trying to wait again for a reaped child is safe since there's no pid-recycling race.
69+
// But doing so will return an error.
70+
let res = fd.wait();
71+
assert_matches!(res,Err(e)if e.raw_os_error() ==Some(libc::ECHILD));
72+
73+
// Ditto for additional attempts to kill an already-dead child.
74+
let res = fd.kill();
75+
assert_matches!(res,Err(e)if e.raw_os_error() ==Some(libc::ESRCH));
76+
}
77+
78+
fnprobe_pidfd_support() ->bool{
79+
// pidfds require the pidfd_open syscall
80+
let our_pid =crate::process::id();
81+
let pidfd =unsafe{ libc::syscall(libc::SYS_pidfd_open, our_pid,0)};
82+
if pidfd >=0{
83+
unsafe{ libc::close(pidfdasRawFd)};
84+
true
85+
}else{
86+
false
87+
}
88+
}

‎library/std/src/sys/pal/unix/mod.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ pub mod io;
2020
pubmod kernel_copy;
2121
#[cfg(target_os ="l4re")]
2222
mod l4re;
23+
#[cfg(target_os ="linux")]
24+
pubmod linux;
2325
#[cfg(not(target_os ="l4re"))]
2426
pubmod net;
2527
#[cfg(target_os ="l4re")]

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp