use super::ProcessHandle;
#[cfg(any(unix, windows))]
use super::termination::GracefulShutdown;
use crate::output_stream::OutputStream;
use crate::panic_on_drop::PanicOnDrop;
#[cfg(any(unix, windows))]
use crate::terminate_on_drop::TerminateOnDrop;
#[derive(Debug)]
pub(crate) enum DropMode {
Armed { panic: PanicOnDrop },
Disarmed,
}
impl<Stdout, Stderr> Drop for ProcessHandle<Stdout, Stderr>
where
Stdout: OutputStream,
Stderr: OutputStream,
{
fn drop(&mut self) {
match &self.drop_mode {
DropMode::Armed { .. } => {
if let Err(err) = self.send_kill_signal() {
tracing::warn!(
process = %self.name,
error = %err,
"Failed to kill process while dropping an armed ProcessHandle"
);
}
}
DropMode::Disarmed => {}
}
}
}
impl<Stdout, Stderr> ProcessHandle<Stdout, Stderr>
where
Stdout: OutputStream,
Stderr: OutputStream,
{
pub(super) fn new_armed_drop_mode() -> DropMode {
DropMode::Armed {
panic: armed_panic_guard(),
}
}
pub fn must_be_terminated(&mut self) {
match &mut self.drop_mode {
DropMode::Armed { panic } if panic.is_armed() => {
}
_ => {
self.drop_mode = DropMode::Armed {
panic: armed_panic_guard(),
};
}
}
}
pub fn must_not_be_terminated(&mut self) {
if let DropMode::Armed { panic } = &mut self.drop_mode {
panic.defuse();
}
self.drop_mode = DropMode::Disarmed;
}
#[doc(hidden)]
pub fn is_drop_armed(&self) -> bool {
matches!(&self.drop_mode, DropMode::Armed { panic } if panic.is_armed())
}
#[doc(hidden)]
pub fn is_drop_disarmed(&self) -> bool {
matches!(self.drop_mode, DropMode::Disarmed)
}
#[cfg(any(unix, windows))]
pub fn terminate_on_drop(self, shutdown: GracefulShutdown) -> TerminateOnDrop<Stdout, Stderr> {
TerminateOnDrop {
process_handle: self,
shutdown,
}
}
}
fn armed_panic_guard() -> PanicOnDrop {
PanicOnDrop::new(
"tokio_process_tools::ProcessHandle",
"The process was not terminated.",
"Successfully call `wait_for_completion`, `terminate`, or `kill`, or call `must_not_be_terminated` before the type is dropped!",
)
}