Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update nix to 0.28. #102

Merged
merged 1 commit into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}
}
Loading