#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KillPhase {
Graceful,
Escalate,
Verify,
}
impl KillPhase {
pub fn label(self) -> &'static str {
match self {
KillPhase::Graceful => "GRACEFUL",
KillPhase::Escalate => "ESCALATE",
KillPhase::Verify => "VERIFY",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KillStep {
pub phase: KillPhase,
pub pid: u32,
pub grace_ms: u64,
}
pub const DEFAULT_GRACE_MS: u64 = 2_000;
pub fn plan_kill(root_pid: u32, grace_ms: u64) -> Vec<KillStep> {
vec![
KillStep {
phase: KillPhase::Graceful,
pid: root_pid,
grace_ms,
},
KillStep {
phase: KillPhase::Escalate,
pid: root_pid,
grace_ms: 0,
},
KillStep {
phase: KillPhase::Verify,
pid: root_pid,
grace_ms: 0,
},
]
}
pub fn advance(phase: KillPhase, survivors: bool) -> Option<KillPhase> {
match (phase, survivors) {
(KillPhase::Graceful, true) => Some(KillPhase::Escalate),
(KillPhase::Graceful, false) => Some(KillPhase::Verify),
(KillPhase::Escalate, _) => Some(KillPhase::Verify),
(KillPhase::Verify, false) => None,
(KillPhase::Verify, true) => None,
}
}
pub fn cleanup_ok(phase: KillPhase, survivors: bool) -> bool {
phase == KillPhase::Verify && !survivors
}
#[cfg(test)]
mod proctree_tests {
use super::*;
#[test]
fn plan_always_has_all_three_steps_in_order() {
let plan = plan_kill(4242, DEFAULT_GRACE_MS);
let phases: Vec<KillPhase> = plan.iter().map(|s| s.phase).collect();
assert_eq!(
phases,
vec![KillPhase::Graceful, KillPhase::Escalate, KillPhase::Verify]
);
assert!(plan.iter().all(|s| s.pid == 4242));
assert_eq!(plan[0].grace_ms, DEFAULT_GRACE_MS);
}
#[test]
fn graceful_with_survivors_must_escalate() {
assert_eq!(
advance(KillPhase::Graceful, true),
Some(KillPhase::Escalate)
);
assert_eq!(advance(KillPhase::Graceful, false), Some(KillPhase::Verify));
}
#[test]
fn verify_is_terminal_and_honest() {
assert_eq!(advance(KillPhase::Escalate, true), Some(KillPhase::Verify));
assert_eq!(advance(KillPhase::Verify, true), None);
assert_eq!(advance(KillPhase::Verify, false), None);
assert!(cleanup_ok(KillPhase::Verify, false));
assert!(!cleanup_ok(KillPhase::Verify, true));
assert!(!cleanup_ok(KillPhase::Escalate, false));
}
}