use crate::errors::Result;
use std::process::Child;
use std::time::Duration;
#[cfg(target_os = "linux")]
pub mod timerfd_impl;
#[cfg(target_os = "macos")]
pub mod kqueue_impl;
pub fn wait_with_precise_timeout(
child: Child,
timeout: Duration,
) -> Result<std::process::ExitStatus> {
#[cfg(target_os = "linux")]
return timerfd_impl::wait_with_timerfd_timeout(child, timeout);
#[cfg(target_os = "macos")]
return kqueue_impl::wait_with_kqueue_timeout(child, timeout);
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
{
wait_with_polling_timeout(child, timeout)
}
}
#[allow(dead_code)]
fn wait_with_polling_timeout(
mut child: Child,
timeout: Duration,
) -> Result<std::process::ExitStatus> {
use std::thread;
let start = std::time::Instant::now();
loop {
match child.try_wait() {
Ok(Some(status)) => return Ok(status),
Ok(None) => {
if start.elapsed() >= timeout {
return Err(crate::errors::StandbyError::ProcessError(
"Process timeout".to_string(),
));
}
thread::sleep(Duration::from_millis(10));
}
Err(e) => {
return Err(crate::errors::StandbyError::ProcessError(format!(
"Failed to wait for process: {}",
e
)));
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_polling_immediate_exit() {
let child = std::process::Command::new("true")
.spawn()
.expect("failed to spawn");
let result = wait_with_polling_timeout(child, Duration::from_secs(5));
assert!(result.is_ok());
}
}