use std::future::Future;
use async_signal::{Signal, Signals};
use futures::StreamExt;
use nix::{
sys::signal::{kill, Signal::SIGQUIT},
unistd::Pid,
};
use crate::{
attach::attacher::{Attacher, AttacherSignal},
internal::{attach_file_path, AutoDropFile},
};
pub struct UnixAttacher;
impl Attacher for UnixAttacher {
type Signal = UnixAttacherSignal;
fn signal(pid: u32) -> Result<Self::Signal, Box<dyn std::error::Error>> {
Ok(UnixAttacherSignal { pid, file: None })
}
fn signaled() -> impl Future<Output = Result<(), Box<dyn std::error::Error>>> {
let signals = Signals::new([Signal::Quit]);
async move {
let mut signals = signals?;
while let Some(signal) = signals.next().await {
if let Ok(signal) = signal {
if signal == Signal::Quit {
let attach_file_path = attach_file_path(std::process::id())?;
if attach_file_path.exists() {
break;
}
}
}
}
Ok(())
}
}
}
pub struct UnixAttacherSignal {
pid: u32,
file: Option<AutoDropFile>,
}
impl AttacherSignal for UnixAttacherSignal {
async fn send(&mut self) -> Result<(), Box<dyn std::error::Error>> {
if self
.file
.as_ref()
.map(|file| file.exists())
.transpose()?
.is_none_or(|exists| !exists)
{
self.file = Some(AutoDropFile::create(attach_file_path(self.pid)?)?);
}
kill(Pid::from_raw(self.pid as _), SIGQUIT)?;
Ok(())
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::UnixAttacher;
use crate::attach::attacher::tests::test_attacher;
#[test]
fn test_unix_attacher() {
test_attacher::<UnixAttacher, _>(async {});
}
}