use std::process::Child;
use std::time::Duration;
use crate::errors::{Result, StandbyError};
pub fn wait_with_kqueue_timeout(
mut child: Child,
timeout: Duration,
) -> Result<std::process::ExitStatus> {
use std::thread;
let start = std::time::Instant::now();
let mut poll_interval_ms: u64 = 1;
let max_poll_interval_ms: u64 = 10;
loop {
match child.try_wait() {
Ok(Some(status)) => return Ok(status),
Ok(None) => {
if start.elapsed() >= timeout {
return Err(StandbyError::ProcessError("Process timeout".to_string()));
}
if poll_interval_ms < max_poll_interval_ms {
poll_interval_ms = std::cmp::min(poll_interval_ms * 2, max_poll_interval_ms);
}
thread::sleep(Duration::from_millis(poll_interval_ms));
}
Err(e) => {
return Err(StandbyError::ProcessError(format!(
"Failed to wait for process: {}",
e
)));
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_kqueue_immediate_exit() {
let child = std::process::Command::new("true")
.spawn()
.expect("failed to spawn");
let result = wait_with_kqueue_timeout(child, Duration::from_secs(5));
assert!(result.is_ok());
}
#[test]
fn test_kqueue_timeout() {
let child = std::process::Command::new("sleep")
.arg("10")
.spawn()
.expect("failed to spawn");
let result = wait_with_kqueue_timeout(child, Duration::from_millis(100));
assert!(result.is_err());
}
}