Skip to content

Commit a266bd8

Browse files
committed
Split do_fork into two
1 parent 5ac8a31 commit a266bd8

File tree

1 file changed

+73
-69
lines changed

1 file changed

+73
-69
lines changed

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

Lines changed: 73 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -118,84 +118,88 @@ impl Command {
118118
}
119119
}
120120

121-
// Attempts to fork the process. If successful, returns
122-
// Ok((0, -1)) in the child, and Ok((child_pid, child_pidfd)) in the parent.
121+
// Attempts to fork the process. If successful, returns Ok((0, -1))
122+
// in the child, and Ok((child_pid, -1)) in the parent.
123+
#[cfg(not(target_os = "linux"))]
124+
fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
125+
cvt(unsafe { libc::fork() }).map(|res| (res, -1))
126+
}
127+
128+
// Attempts to fork the process. If successful, returns Ok((0, -1))
129+
// in the child, and Ok((child_pid, child_pidfd)) in the parent.
130+
#[cfg(target_os = "linux")]
123131
fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
132+
use crate::sync::atomic::{AtomicBool, Ordering};
133+
134+
static HAS_CLONE3: AtomicBool = AtomicBool::new(true);
135+
const CLONE_PIDFD: u64 = 0x00001000;
136+
137+
#[repr(C)]
138+
struct clone_args {
139+
flags: u64,
140+
pidfd: u64,
141+
child_tid: u64,
142+
parent_tid: u64,
143+
exit_signal: u64,
144+
stack: u64,
145+
stack_size: u64,
146+
tls: u64,
147+
set_tid: u64,
148+
set_tid_size: u64,
149+
cgroup: u64,
150+
}
151+
152+
syscall! {
153+
fn clone3(cl_args: *mut clone_args, len: libc::size_t) -> libc::c_long
154+
}
155+
124156
// If we fail to create a pidfd for any reason, this will
125-
// stay as -1, which indicates an error
157+
// stay as -1, which indicates an error.
126158
let mut pidfd: pid_t = -1;
127159

128-
// On Linux, attempt to use the `clone3` syscall, which
129-
// supports more arguments (in particular, the ability to create a pidfd).
130-
// If this fails, we will fall through this block to a call to `fork()`
131-
#[cfg(target_os = "linux")]
132-
{
133-
use crate::sync::atomic::{AtomicBool, Ordering};
134-
static HAS_CLONE3: AtomicBool = AtomicBool::new(true);
135-
136-
const CLONE_PIDFD: u64 = 0x00001000;
137-
138-
#[repr(C)]
139-
struct clone_args {
140-
flags: u64,
141-
pidfd: u64,
142-
child_tid: u64,
143-
parent_tid: u64,
144-
exit_signal: u64,
145-
stack: u64,
146-
stack_size: u64,
147-
tls: u64,
148-
set_tid: u64,
149-
set_tid_size: u64,
150-
cgroup: u64,
151-
}
152-
153-
syscall! {
154-
fn clone3(cl_args: *mut clone_args, len: libc::size_t) -> libc::c_long
160+
// Attempt to use the `clone3` syscall, which supports more arguments
161+
// (in particular, the ability to create a pidfd). If this fails,
162+
// we will fall through this block to a call to `fork()`
163+
if HAS_CLONE3.load(Ordering::Relaxed) {
164+
let mut flags = 0;
165+
if self.create_pidfd {
166+
flags |= CLONE_PIDFD;
155167
}
156168

157-
if HAS_CLONE3.load(Ordering::Relaxed) {
158-
let mut flags = 0;
159-
if self.create_pidfd {
160-
flags |= CLONE_PIDFD;
161-
}
162-
163-
let mut args = clone_args {
164-
flags,
165-
pidfd: &mut pidfd as *mut pid_t as u64,
166-
child_tid: 0,
167-
parent_tid: 0,
168-
exit_signal: libc::SIGCHLD as u64,
169-
stack: 0,
170-
stack_size: 0,
171-
tls: 0,
172-
set_tid: 0,
173-
set_tid_size: 0,
174-
cgroup: 0,
175-
};
176-
177-
let args_ptr = &mut args as *mut clone_args;
178-
let args_size = crate::mem::size_of::<clone_args>();
179-
180-
let res = cvt(unsafe { clone3(args_ptr, args_size) });
181-
match res {
182-
Ok(n) => return Ok((n as pid_t, pidfd)),
183-
Err(e) => match e.raw_os_error() {
184-
// Multiple threads can race to execute this store,
185-
// but that's fine - that just means that multiple threads
186-
// will have tried and failed to execute the same syscall,
187-
// with no other side effects.
188-
Some(libc::ENOSYS) => HAS_CLONE3.store(false, Ordering::Relaxed),
189-
// Fallback to fork if `EPERM` is returned. (e.g. blocked by seccomp)
190-
Some(libc::EPERM) => {}
191-
_ => return Err(e),
192-
},
193-
}
169+
let mut args = clone_args {
170+
flags,
171+
pidfd: &mut pidfd as *mut pid_t as u64,
172+
child_tid: 0,
173+
parent_tid: 0,
174+
exit_signal: libc::SIGCHLD as u64,
175+
stack: 0,
176+
stack_size: 0,
177+
tls: 0,
178+
set_tid: 0,
179+
set_tid_size: 0,
180+
cgroup: 0,
181+
};
182+
183+
let args_ptr = &mut args as *mut clone_args;
184+
let args_size = crate::mem::size_of::<clone_args>();
185+
186+
let res = cvt(unsafe { clone3(args_ptr, args_size) });
187+
match res {
188+
Ok(n) => return Ok((n as pid_t, pidfd)),
189+
Err(e) => match e.raw_os_error() {
190+
// Multiple threads can race to execute this store,
191+
// but that's fine - that just means that multiple threads
192+
// will have tried and failed to execute the same syscall,
193+
// with no other side effects.
194+
Some(libc::ENOSYS) => HAS_CLONE3.store(false, Ordering::Relaxed),
195+
// Fallback to fork if `EPERM` is returned. (e.g. blocked by seccomp)
196+
Some(libc::EPERM) => {}
197+
_ => return Err(e),
198+
},
194199
}
195200
}
196201

197-
// If we get here, we are either not on Linux,
198-
// or we are on Linux and the 'clone3' syscall does not exist
202+
// If we get here, the 'clone3' syscall does not exist
199203
// or we do not have permission to call it
200204
cvt(unsafe { libc::fork() }).map(|res| (res, pidfd))
201205
}

0 commit comments

Comments
 (0)