ipc: check for PID liveness via libc:kill
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I961c138cf8341bad6a27c450706de11d6a6a6964
This commit is contained in:
parent
614d76fd74
commit
62f3230456
1 changed files with 42 additions and 12 deletions
54
src/ipc.rs
54
src/ipc.rs
|
|
@ -53,6 +53,25 @@ impl From<serde_json::Error> for IpcError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check whether a process with the given PID is still alive.
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn is_process_alive(pid: u32) -> bool {
|
||||||
|
unsafe {
|
||||||
|
if libc::kill(pid as i32, 0) == 0 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
let errno = *libc::__errno_location();
|
||||||
|
// EPERM means the process exists but we can't signal it.
|
||||||
|
errno == libc::EPERM
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
fn is_process_alive(_pid: u32) -> bool {
|
||||||
|
// Cannot verify on non-Unix; assume alive to stay safe.
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents an ongoing operation tracked in IPC
|
/// Represents an ongoing operation tracked in IPC
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct OngoingOperation {
|
pub struct OngoingOperation {
|
||||||
|
|
@ -279,7 +298,7 @@ impl IpcCoordinator {
|
||||||
let mut operations = self.load_operations()?;
|
let mut operations = self.load_operations()?;
|
||||||
log::debug!("Loaded {} existing operations", operations.len());
|
log::debug!("Loaded {} existing operations", operations.len());
|
||||||
|
|
||||||
// Clean up stale operations (older than 10 minutes)
|
// Clean up stale operations (older than 10 minutes or with dead PIDs)
|
||||||
let now = SystemTime::now()
|
let now = SystemTime::now()
|
||||||
.duration_since(SystemTime::UNIX_EPOCH)
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
.unwrap_or(Duration::ZERO)
|
.unwrap_or(Duration::ZERO)
|
||||||
|
|
@ -289,18 +308,21 @@ impl IpcCoordinator {
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|op| {
|
.filter(|op| {
|
||||||
op.status == OperationStatus::Running
|
op.status == OperationStatus::Running
|
||||||
&& now.saturating_sub(op.started_at) > 600
|
&& (now.saturating_sub(op.started_at) > 600
|
||||||
|
|| !is_process_alive(op.pid))
|
||||||
})
|
})
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
operations.retain(|op| {
|
operations.retain(|op| {
|
||||||
if op.status == OperationStatus::Running
|
if op.status == OperationStatus::Running {
|
||||||
&& now.saturating_sub(op.started_at) > 600
|
if !is_process_alive(op.pid) {
|
||||||
{
|
return false; // Remove dead operations
|
||||||
false // Remove stale operations
|
}
|
||||||
} else {
|
if now.saturating_sub(op.started_at) > 600 {
|
||||||
true
|
return false; // Remove old operations
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
true
|
||||||
});
|
});
|
||||||
|
|
||||||
if stale_count > 0 {
|
if stale_count > 0 {
|
||||||
|
|
@ -311,7 +333,9 @@ impl IpcCoordinator {
|
||||||
let conflicting: Vec<_> = operations
|
let conflicting: Vec<_> = operations
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|op| {
|
.filter(|op| {
|
||||||
op.r#type == operation_type && op.status == OperationStatus::Running
|
op.r#type == operation_type
|
||||||
|
&& op.status == OperationStatus::Running
|
||||||
|
&& is_process_alive(op.pid)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
@ -403,7 +427,9 @@ impl IpcCoordinator {
|
||||||
let conflicts: Vec<_> = operations
|
let conflicts: Vec<_> = operations
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|op| {
|
.filter(|op| {
|
||||||
op.r#type == operation_type && op.status == OperationStatus::Running
|
op.r#type == operation_type
|
||||||
|
&& op.status == OperationStatus::Running
|
||||||
|
&& is_process_alive(op.pid)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
@ -426,7 +452,9 @@ impl IpcCoordinator {
|
||||||
pub fn has_running_operation(&self, operation_type: OperationType) -> bool {
|
pub fn has_running_operation(&self, operation_type: OperationType) -> bool {
|
||||||
let operations = self.load_operations().unwrap_or_default();
|
let operations = self.load_operations().unwrap_or_default();
|
||||||
operations.iter().any(|op| {
|
operations.iter().any(|op| {
|
||||||
op.r#type == operation_type && op.status == OperationStatus::Running
|
op.r#type == operation_type
|
||||||
|
&& op.status == OperationStatus::Running
|
||||||
|
&& is_process_alive(op.pid)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -439,7 +467,9 @@ impl IpcCoordinator {
|
||||||
operations
|
operations
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|op| {
|
.filter(|op| {
|
||||||
op.r#type == operation_type && op.status == OperationStatus::Running
|
op.r#type == operation_type
|
||||||
|
&& op.status == OperationStatus::Running
|
||||||
|
&& is_process_alive(op.pid)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue