Skip to content

Commit

Permalink
Merge pull request #1472 from GuillaumeGomez/improve-linux-process
Browse files Browse the repository at this point in the history
Improve linux code to update processes
  • Loading branch information
GuillaumeGomez authored Mar 4, 2025
2 parents baa46ef + 3992e4d commit 26f7653
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 65 deletions.
131 changes: 67 additions & 64 deletions src/unix/linux/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,86 +502,87 @@ fn retrieve_all_new_process_info(
Process { inner: p }
}

pub(crate) fn _get_process_data(
path: &Path,
proc_list: &mut HashMap<Pid, Process>,
pid: Pid,
fn update_existing_process(
proc: &mut Process,
parent_pid: Option<Pid>,
uptime: u64,
info: &SystemInfo,
refresh_kind: ProcessRefreshKind,
) -> Result<(Option<Process>, Pid), ()> {
let data;
let parts = if let Some(ref mut entry) = proc_list.get_mut(&pid) {
let entry = &mut entry.inner;
data = if let Some(mut f) = entry.stat_file.take() {
match get_all_data_from_file(&mut f, 1024) {
Ok(data) => {
// Everything went fine, we put back the file descriptor.
entry.stat_file = Some(f);
data
}
Err(_) => {
// It's possible that the file descriptor is no longer valid in case the
// original process was terminated and another one took its place.
_get_stat_data(&entry.proc_path, &mut entry.stat_file)?
}
let entry = &mut proc.inner;
let data = if let Some(mut f) = entry.stat_file.take() {
match get_all_data_from_file(&mut f, 1024) {
Ok(data) => {
// Everything went fine, we put back the file descriptor.
entry.stat_file = Some(f);
data
}
Err(_) => {
// It's possible that the file descriptor is no longer valid in case the
// original process was terminated and another one took its place.
_get_stat_data(&entry.proc_path, &mut entry.stat_file)?
}
} else {
_get_stat_data(path, &mut entry.stat_file)?
};
let parts = parse_stat_file(&data).ok_or(())?;
let start_time_without_boot_time = compute_start_time_without_boot_time(&parts, info);

// It's possible that a new process took this same PID when the "original one" terminated.
// If the start time differs, then it means it's not the same process anymore and that we
// need to get all its information, hence why we check it here.
if start_time_without_boot_time == entry.start_time_without_boot_time {
let mut proc_path = PathHandler::new(path);

update_proc_info(
entry,
parent_pid,
refresh_kind,
&mut proc_path,
&parts.str_parts,
uptime,
info,
);

refresh_user_group_ids(entry, &mut proc_path, refresh_kind);
return Ok((None, pid));
}
parts
} else {
let mut stat_file = None;
let data = _get_stat_data(path, &mut stat_file)?;
let parts = parse_stat_file(&data).ok_or(())?;
_get_stat_data(&entry.proc_path, &mut entry.stat_file)?
};
let parts = parse_stat_file(&data).ok_or(())?;
let start_time_without_boot_time = compute_start_time_without_boot_time(&parts, info);

let mut p = retrieve_all_new_process_info(
pid,
// It's possible that a new process took this same PID when the "original one" terminated.
// If the start time differs, then it means it's not the same process anymore and that we
// need to get all its information, hence why we check it here.
if start_time_without_boot_time == entry.start_time_without_boot_time {
let mut proc_path = PathHandler::new(&entry.proc_path);

update_proc_info(
entry,
parent_pid,
&parts,
path,
info,
refresh_kind,
&mut proc_path,
&parts.str_parts,
uptime,
info,
);
p.inner.stat_file = stat_file;
return Ok((Some(p), pid));
};

// If we're here, it means that the PID still exists but it's a different process.
let p =
retrieve_all_new_process_info(pid, parent_pid, &parts, path, info, refresh_kind, uptime);
match proc_list.get_mut(&pid) {
Some(ref mut entry) => **entry = p,
// If it ever enters this case, it means that the process was removed from the HashMap
// in-between with the usage of dark magic.
None => unreachable!(),
refresh_user_group_ids(entry, &mut proc_path, refresh_kind);
return Ok((None, entry.pid));
}
// If we're here, it means that the PID still exists but it's a different process.
let p = retrieve_all_new_process_info(
entry.pid,
parent_pid,
&parts,
&entry.proc_path,
info,
refresh_kind,
uptime,
);
*proc = p;
// Since this PID is already in the HashMap, no need to add it again.
Ok((None, pid))
Ok((None, proc.inner.pid))
}

pub(crate) fn _get_process_data(
path: &Path,
proc_list: &mut HashMap<Pid, Process>,
pid: Pid,
parent_pid: Option<Pid>,
uptime: u64,
info: &SystemInfo,
refresh_kind: ProcessRefreshKind,
) -> Result<(Option<Process>, Pid), ()> {
if let Some(ref mut entry) = proc_list.get_mut(&pid) {
return update_existing_process(entry, parent_pid, uptime, info, refresh_kind);
}
let mut stat_file = None;
let data = _get_stat_data(path, &mut stat_file)?;
let parts = parse_stat_file(&data).ok_or(())?;

let mut p =
retrieve_all_new_process_info(pid, parent_pid, &parts, path, info, refresh_kind, uptime);
p.inner.stat_file = stat_file;
Ok((Some(p), pid))
}

fn old_get_memory(entry: &mut ProcessInner, str_parts: &[&str], info: &SystemInfo) {
Expand Down Expand Up @@ -737,6 +738,8 @@ where
val
}

/// We're forced to read the whole `/proc` folder because if a process died and another took its
/// place, we need to get the task parent (if it's a task).
pub(crate) fn refresh_procs(
proc_list: &mut HashMap<Pid, Process>,
path: &Path,
Expand Down
2 changes: 1 addition & 1 deletion src/windows/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -963,7 +963,7 @@ fn get_proc_env<T: RtlUserProcessParameters>(
let mut begin = 0;
while let Some(offset) = raw_env[begin..].iter().position(|&c| c == 0) {
let end = begin + offset;
if raw_env[begin..end].iter().any(|&c| c == equals) {
if raw_env[begin..end].contains(&equals) {
environ.push(OsString::from_wide(&raw_env[begin..end]));
begin = end + 1;
} else {
Expand Down

0 comments on commit 26f7653

Please sign in to comment.