#![allow(irrefutable_let_patterns)]
#[cfg(any(windows, target_os = "linux"))]
macro_rules! cfg_wait {
($($tt:tt)*) => {$($tt)*};
}
#[cfg(not(any(windows, target_os = "linux")))]
macro_rules! cfg_wait {
($($tt:tt)*) => {};
}
#[cfg(not(windows))]
macro_rules! cfg_signal {
($($tt:tt)*) => {$($tt)*};
}
#[cfg(windows)]
macro_rules! cfg_signal {
($($tt:tt)*) => {};
}
cfg_wait! {
mod wait;
}
cfg_signal! {
mod signal;
}
use std::io;
use std::sync::Mutex;
pub(crate) enum Reaper {
#[cfg(any(windows, target_os = "linux"))]
Wait(wait::Reaper),
#[cfg(not(windows))]
Signal(signal::Reaper),
}
pub(crate) enum ChildGuard {
#[cfg(any(windows, target_os = "linux"))]
Wait(wait::ChildGuard),
#[cfg(not(windows))]
Signal(signal::ChildGuard),
}
pub(crate) enum Lock {
#[cfg(any(windows, target_os = "linux"))]
Wait,
#[cfg(not(windows))]
Signal(signal::Lock),
}
impl Reaper {
pub(crate) fn new() -> Self {
cfg_wait! {
if wait::available() && !cfg!(async_process_force_signal_backend) {
return Self::Wait(wait::Reaper::new());
}
}
cfg_signal! {
return Self::Signal(signal::Reaper::new());
}
#[allow(unreachable_code)]
{
panic!("neither the signal backend nor the waiter backend is available")
}
}
pub(crate) async fn lock(&'static self) -> Lock {
cfg_wait! {
if let Self::Wait(_this) = self {
return Lock::Wait;
}
}
cfg_signal! {
if let Self::Signal(this) = self {
return Lock::Signal(this.lock().await);
}
}
unreachable!()
}
pub(crate) async fn reap(&'static self, lock: Lock) -> ! {
cfg_wait! {
if let (Self::Wait(this), Lock::Wait) = (self, &lock) {
this.reap().await;
}
}
cfg_signal! {
if let (Self::Signal(this), Lock::Signal(lock)) = (self, lock) {
this.reap(lock).await;
}
}
unreachable!()
}
pub(crate) fn register(&'static self, child: std::process::Child) -> io::Result<ChildGuard> {
cfg_wait! {
if let Self::Wait(this) = self {
return this.register(child).map(ChildGuard::Wait);
}
}
cfg_signal! {
if let Self::Signal(this) = self {
return this.register(child).map(ChildGuard::Signal);
}
}
unreachable!()
}
pub(crate) async fn status(
&'static self,
child: &Mutex<crate::ChildGuard>,
) -> io::Result<std::process::ExitStatus> {
cfg_wait! {
if let Self::Wait(this) = self {
return this.status(child).await;
}
}
cfg_signal! {
if let Self::Signal(this) = self {
return this.status(child).await;
}
}
unreachable!()
}
pub(crate) fn has_zombies(&'static self) -> bool {
cfg_wait! {
if let Self::Wait(this) = self {
return this.has_zombies();
}
}
cfg_signal! {
if let Self::Signal(this) = self {
return this.has_zombies();
}
}
unreachable!()
}
}
impl ChildGuard {
pub(crate) fn get_mut(&mut self) -> &mut std::process::Child {
cfg_wait! {
if let Self::Wait(this) = self {
return this.get_mut();
}
}
cfg_signal! {
if let Self::Signal(this) = self {
return this.get_mut();
}
}
unreachable!()
}
pub(crate) fn reap(&mut self, reaper: &'static Reaper) {
cfg_wait! {
if let (Self::Wait(this), Reaper::Wait(reaper)) = (&mut *self, reaper) {
this.reap(reaper);
return;
}
}
cfg_signal! {
if let (Self::Signal(this), Reaper::Signal(reaper)) = (self, reaper) {
this.reap(reaper);
return;
}
}
unreachable!()
}
}