1use std::path::PathBuf;
2
3use super::scoping::session_dir;
4
5fn pid_path(session_key: &str) -> PathBuf {
7 session_dir().join(format!("{session_key}.pid"))
8}
9
10pub fn write_pid(session_key: &str) -> std::io::Result<()> {
12 let path = pid_path(session_key);
13 if let Some(parent) = path.parent() {
14 std::fs::create_dir_all(parent)?;
15 }
16 std::fs::write(&path, std::process::id().to_string())
17}
18
19pub fn remove_pid(session_key: &str) -> std::io::Result<()> {
21 let path = pid_path(session_key);
22 match std::fs::remove_file(&path) {
23 Ok(()) => Ok(()),
24 Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()),
25 Err(e) => Err(e),
26 }
27}
28
29pub fn read_pid(session_key: &str) -> Option<u32> {
34 let path = pid_path(session_key);
35 let contents = std::fs::read_to_string(&path).ok()?;
36 let pid: u32 = contents.trim().parse().ok()?;
37 if is_process_alive(pid) {
38 Some(pid)
39 } else {
40 let _ = std::fs::remove_file(&path);
42 None
43 }
44}
45
46fn is_process_alive(pid: u32) -> bool {
50 let ret = unsafe { libc::kill(pid as libc::pid_t, 0) };
55 if ret == 0 {
56 return true;
57 }
58 std::io::Error::last_os_error().raw_os_error() == Some(libc::EPERM)
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn current_process_is_alive() {
68 assert!(is_process_alive(std::process::id()));
69 }
70
71 #[test]
72 fn bogus_pid_is_not_alive() {
73 assert!(!is_process_alive(4_000_000));
75 }
76}