Auto merge of #124101 - the8472:pidfd-methods, r=cuviper · rust-lang/rust@10e1f5d

@@ -6,20 +6,20 @@

6677

use crate::io::Result;

88

use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};

9-

use crate::process;

9+

use crate::process::{self, ExitStatus};

1010

use crate::sealed::Sealed;

1111

#[cfg(not(doc))]

12-

use crate::sys::fd::FileDesc;

12+

use crate::sys::{fd::FileDesc, linux::pidfd::PidFd as InnerPidFd};

1313

use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};

14141515

#[cfg(doc)]

16-

struct FileDesc;

16+

struct InnerPidFd;

17171818

/// This type represents a file descriptor that refers to a process.

1919

///

2020

/// A `PidFd` can be obtained by setting the corresponding option on [`Command`]

2121

/// with [`create_pidfd`]. Subsequently, the created pidfd can be retrieved

22-

/// from the [`Child`] by calling [`pidfd`] or [`take_pidfd`].

22+

/// from the [`Child`] by calling [`pidfd`] or [`into_pidfd`].

2323

///

2424

/// Example:

2525

/// ```no_run

@@ -33,7 +33,7 @@ struct FileDesc;

3333

/// .expect("Failed to spawn child");

3434

///

3535

/// let pidfd = child

36-

/// .take_pidfd()

36+

/// .into_pidfd()

3737

/// .expect("Failed to retrieve pidfd");

3838

///

3939

/// // The file descriptor will be closed when `pidfd` is dropped.

@@ -44,66 +44,101 @@ struct FileDesc;

4444

/// [`create_pidfd`]: CommandExt::create_pidfd

4545

/// [`Child`]: process::Child

4646

/// [`pidfd`]: fn@ChildExt::pidfd

47-

/// [`take_pidfd`]: ChildExt::take_pidfd

47+

/// [`into_pidfd`]: ChildExt::into_pidfd

4848

/// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html

4949

#[derive(Debug)]

50+

#[repr(transparent)]

5051

pub struct PidFd {

51-

inner: FileDesc,

52+

inner: InnerPidFd,

5253

}

535454-

impl AsInner<FileDesc> for PidFd {

55+

impl PidFd {

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+

pub fn kill(&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+

pub fn wait(&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+

pub fn try_wait(&self) -> Result<Option<ExitStatus>> {

85+

Ok(self.inner.try_wait()?.map(FromInner::from_inner))

86+

}

87+

}

88+89+

impl AsInner<InnerPidFd> for PidFd {

5590

#[inline]

56-

fn as_inner(&self) -> &FileDesc {

91+

fn as_inner(&self) -> &InnerPidFd {

5792

&self.inner

5893

}

5994

}

609561-

impl FromInner<FileDesc> for PidFd {

62-

fn from_inner(inner: FileDesc) -> PidFd {

96+

impl FromInner<InnerPidFd> for PidFd {

97+

fn from_inner(inner: InnerPidFd) -> PidFd {

6398

PidFd { inner }

6499

}

65100

}

6610167-

impl IntoInner<FileDesc> for PidFd {

68-

fn into_inner(self) -> FileDesc {

102+

impl IntoInner<InnerPidFd> for PidFd {

103+

fn into_inner(self) -> InnerPidFd {

69104

self.inner

70105

}

71106

}

7210773108

impl AsRawFd for PidFd {

74109

#[inline]

75110

fn as_raw_fd(&self) -> RawFd {

76-

self.as_inner().as_raw_fd()

111+

self.as_inner().as_inner().as_raw_fd()

77112

}

78113

}

7911480115

impl FromRawFd for PidFd {

81116

unsafe fn from_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

}

8512086121

impl IntoRawFd for PidFd {

87122

fn into_raw_fd(self) -> RawFd {

88-

self.into_inner().into_raw_fd()

123+

self.into_inner().into_inner().into_raw_fd()

89124

}

90125

}

9112692127

impl AsFd for PidFd {

93128

fn as_fd(&self) -> BorrowedFd<'_> {

94-

self.as_inner().as_fd()

129+

self.as_inner().as_inner().as_fd()

95130

}

96131

}

9713298133

impl From<OwnedFd> for PidFd {

99134

fn from(fd: OwnedFd) -> Self {

100-

Self::from_inner(FileDesc::from_inner(fd))

135+

Self::from_inner(InnerPidFd::from_inner(FileDesc::from_inner(fd)))

101136

}

102137

}

103138104139

impl From<PidFd> for OwnedFd {

105140

fn from(pid_fd: PidFd) -> Self {

106-

pid_fd.into_inner().into_inner()

141+

pid_fd.into_inner().into_inner().into_inner()

107142

}

108143

}

109144

@@ -124,18 +159,26 @@ pub trait ChildExt: Sealed {

124159

/// [`Child`]: process::Child

125160

fn pidfd(&self) -> Result<&PidFd>;

126161127-

/// Takes ownership of the [`PidFd`] created for this [`Child`], if available.

162+

/// Returns the [`PidFd`] created for this [`Child`], if available.

163+

/// Otherwise self is returned.

128164

///

129165

/// A pidfd will only be available if its creation was requested with

130166

/// [`create_pidfd`] when the corresponding [`Command`] was created.

131167

///

168+

/// Taking ownership of the PidFd consumes the Child to avoid pid reuse

169+

/// races. Use [`pidfd`] and [`BorrowedFd::try_clone_to_owned`] if

170+

/// you don't want to disassemble the Child yet.

171+

///

132172

/// Even if requested, a pidfd may not be available due to an older

133173

/// version of Linux being in use, or if some other error occurred.

134174

///

135175

/// [`Command`]: process::Command

136176

/// [`create_pidfd`]: CommandExt::create_pidfd

177+

/// [`pidfd`]: ChildExt::pidfd

137178

/// [`Child`]: process::Child

138-

fn take_pidfd(&mut self) -> Result<PidFd>;

179+

fn into_pidfd(self) -> crate::result::Result<PidFd, Self>

180+

where

181+

Self: Sized;

139182

}

140183141184

/// Os-specific extensions for [`Command`]

@@ -146,7 +189,7 @@ pub trait CommandExt: Sealed {

146189

/// spawned by this [`Command`].

147190

/// By default, no pidfd will be created.

148191

///

149-

/// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd`].

192+

/// The pidfd can be retrieved from the child with [`pidfd`] or [`into_pidfd`].

150193

///

151194

/// A pidfd will only be created if it is possible to do so

152195

/// in a guaranteed race-free manner. Otherwise, [`pidfd`] will return an error.

@@ -160,7 +203,7 @@ pub trait CommandExt: Sealed {

160203

/// [`Command`]: process::Command

161204

/// [`Child`]: process::Child

162205

/// [`pidfd`]: fn@ChildExt::pidfd

163-

/// [`take_pidfd`]: ChildExt::take_pidfd

206+

/// [`into_pidfd`]: ChildExt::into_pidfd

164207

fn create_pidfd(&mut self, val: bool) -> &mut process::Command;

165208

}

166209