Skip to content

Commit

Permalink
Update nix to 0.28.
Browse files Browse the repository at this point in the history
  • Loading branch information
mstange committed Feb 26, 2024
1 parent bceaaf7 commit 8b9809f
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 35 deletions.
11 changes: 9 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion samply/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ sysctl = "0.5.4"
parking_lot = "0.12.1"
num_cpus = "1.13.1"
uname = "0.1.1"
nix = { version = "0.27.1", features = ["fs", "process"] }
nix = { version = "0.28", features = ["fs", "process"] }

[dependencies.object]
default-features = false
Expand Down
63 changes: 31 additions & 32 deletions samply/src/linux/process.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
use libc::execvp;
use nix::sys::wait::WaitStatus;
use nix::unistd::Pid;

use std::ffi::{CString, OsStr, OsString};
use std::os::fd::{AsFd, AsRawFd, IntoRawFd, OwnedFd};
use std::os::raw::c_char;
use std::os::unix::prelude::{ExitStatusExt, OsStrExt};
use std::process::ExitStatus;

/// Allows launching a command in a suspended state, so that we can know its
/// pid and initialize profiling before proceeding to execute the command.
pub struct SuspendedLaunchedProcess {
pid: u32,
send_end_of_resume_pipe: i32,
recv_end_of_execerr_pipe: i32,
pid: Pid,
send_end_of_resume_pipe: OwnedFd,
recv_end_of_execerr_pipe: OwnedFd,
}

impl SuspendedLaunchedProcess {
Expand All @@ -34,16 +37,15 @@ impl SuspendedLaunchedProcess {
match unsafe { nix::unistd::fork() }.expect("Fork failed") {
nix::unistd::ForkResult::Child => {
// std::panic::always_abort();
nix::unistd::close(resume_sp).unwrap();
nix::unistd::close(execerr_rp).unwrap();
nix::unistd::close(resume_sp.into_raw_fd()).unwrap();
nix::unistd::close(execerr_rp.into_raw_fd()).unwrap();
Self::run_child(resume_rp, execerr_sp, &argv)
}
nix::unistd::ForkResult::Parent { child } => {
nix::unistd::close(resume_rp)?;
nix::unistd::close(execerr_sp)?;
let pid = child.as_raw() as u32;
nix::unistd::close(resume_rp.into_raw_fd())?;
nix::unistd::close(execerr_sp.into_raw_fd())?;
Ok(Self {
pid,
pid: child,
send_end_of_resume_pipe: resume_sp,
recv_end_of_execerr_pipe: execerr_rp,
})
Expand All @@ -52,21 +54,22 @@ impl SuspendedLaunchedProcess {
}

pub fn pid(&self) -> u32 {
self.pid
self.pid.as_raw() as u32
}

const EXECERR_MSG_FOOTER: [u8; 4] = *b"NOEX";

pub fn unsuspend_and_run(self) -> std::io::Result<RunningProcess> {
// Send a byte to the child process.
nix::unistd::write(self.send_end_of_resume_pipe, &[0x42])?;
nix::unistd::close(self.send_end_of_resume_pipe)?;
nix::unistd::write(self.send_end_of_resume_pipe.as_fd(), &[0x42])?;
nix::unistd::close(self.send_end_of_resume_pipe.into_raw_fd())?;

// Wait for the child to indicate success or failure of the execve call.
// loop for EINTR
loop {
let mut bytes = [0; 8];
let read_result = nix::unistd::read(self.recv_end_of_execerr_pipe, &mut bytes);
let read_result =
nix::unistd::read(self.recv_end_of_execerr_pipe.as_raw_fd(), &mut bytes);

// The parent has replied! Or exited.
match read_result {
Expand All @@ -85,10 +88,7 @@ impl SuspendedLaunchedProcess {
"Validation on the execerr pipe failed: {bytes:?}",
);
let errno = i32::from_be_bytes([errno[0], errno[1], errno[2], errno[3]]);
let mut exit_status: i32 = 0;
let _pid = unsafe {
libc::waitpid(self.pid as i32, &mut exit_status as *mut libc::c_int, 0)
};
let _wait_status = nix::sys::wait::waitpid(self.pid, None);
return Err(std::io::Error::from_raw_os_error(errno));
}
Ok(_) => {
Expand All @@ -98,11 +98,8 @@ impl SuspendedLaunchedProcess {

// This case is very unexpected and we will panic, after making sure that the child has
// fully executed.
let mut exit_status: i32 = 0;
let waitpid_res = unsafe {
libc::waitpid(self.pid as i32, &mut exit_status as *mut libc::c_int, 0)
};
nix::errno::Errno::result(waitpid_res).expect("waitpid should always succeed");
let _status = nix::sys::wait::waitpid(self.pid, None)
.expect("waitpid should always succeed");

panic!("short read on the execerr pipe")
}
Expand All @@ -116,8 +113,8 @@ impl SuspendedLaunchedProcess {

/// Executed in the forked child process. This function never returns.
fn run_child(
recv_end_of_resume_pipe: i32,
send_end_of_execerr_pipe: i32,
recv_end_of_resume_pipe: OwnedFd,
send_end_of_execerr_pipe: OwnedFd,
argv: &[*const c_char],
) -> ! {
// Wait for the parent to send us a byte through the pipe.
Expand All @@ -126,7 +123,7 @@ impl SuspendedLaunchedProcess {
// loop to handle EINTR
loop {
let mut buf = [0];
let read_result = nix::unistd::read(recv_end_of_resume_pipe, &mut buf);
let read_result = nix::unistd::read(recv_end_of_resume_pipe.as_raw_fd(), &mut buf);

// The parent has replied! Or exited.
match read_result {
Expand All @@ -146,7 +143,7 @@ impl SuspendedLaunchedProcess {

// But we got here! This can happen if the command doesn't exist.
// Return the error number via the "execerr" pipe.
let errno = nix::errno::errno().to_be_bytes();
let errno = nix::errno::Errno::last_raw().to_be_bytes();
let bytes = [
errno[0],
errno[1],
Expand All @@ -172,16 +169,18 @@ impl SuspendedLaunchedProcess {
}

pub struct RunningProcess {
pid: u32,
pid: Pid,
}

impl RunningProcess {
pub fn wait(self) -> Result<std::process::ExitStatus, nix::errno::Errno> {
let mut exit_status: i32 = 0;
let _pid =
unsafe { libc::waitpid(self.pid as i32, &mut exit_status as *mut libc::c_int, 0) };
nix::errno::Errno::result(nix::errno::errno())?;
let exit_status = ExitStatus::from_raw(exit_status);
let wait_status = nix::sys::wait::waitpid(self.pid, None)?;
let exit_status = match wait_status {
WaitStatus::Exited(_pid, exit_code) => ExitStatus::from_raw(exit_code),
wait_status => {
panic!("Unexpected waitpid result: {wait_status:?}");
}
};
Ok(exit_status)
}
}

0 comments on commit 8b9809f

Please sign in to comment.