use std::io;
use std::time::Duration;
use tokio::process::{Child, Command};
#[cfg(any(not(unix), target_os = "linux", target_os = "freebsd"))]
compile_error!(
"sys::unix is the catch-all POSIX process-group backend; Linux (sys::linux) \
and FreeBSD (sys::freebsd) have their own, and non-unix targets have none"
);
use crate::Mechanism;
#[cfg(feature = "process-control")]
use crate::Signal;
#[cfg(feature = "limits")]
use crate::limits::{LimitEvidence, ResourceLimits};
#[cfg(feature = "process-control")]
use crate::member::MemberInfo;
#[cfg(feature = "stats")]
use crate::stats::ProcessGroupStats;
use crate::sys::pgroup::ProcessGroup;
#[cfg(feature = "stats")]
use crate::sys::{ProcIdentity, ProcMetrics};
pub(crate) struct Job {
group: ProcessGroup,
}
impl Job {
pub(crate) fn new(#[cfg(feature = "limits")] limits: &ResourceLimits) -> io::Result<Self> {
#[cfg(feature = "limits")]
if limits.any() {
return Err(io::Error::new(
io::ErrorKind::Unsupported,
"resource limits require a cgroup or Job Object; unavailable on this target",
));
}
Ok(Job {
group: ProcessGroup::new(),
})
}
pub(crate) fn spawn(
&self,
cmd: &mut Command,
opts: &crate::sys::SpawnOptions,
) -> io::Result<Child> {
self.group.spawn(cmd, opts)
}
#[cfg(feature = "pty")]
pub(crate) fn spawn_pty(
&self,
cmd: &mut Command,
opts: &crate::sys::SpawnOptions,
_env: Option<Vec<(std::ffi::OsString, std::ffi::OsString)>>,
) -> io::Result<crate::sys::pty::PtySpawn> {
let displaced = std::cell::Cell::new(crate::sys::DisplacedSpare::default());
crate::sys::pty::spawn_pty(
cmd,
opts,
|c, o| {
let (child, spare) = self.group.spawn_displacing_spare(c, o)?;
displaced.set(spare);
Ok(child)
},
|pid| self.rollback_pty_spawn(pid, displaced.take()),
)
}
#[cfg(feature = "pty")]
pub(crate) fn rollback_pty_spawn(&self, pid: u32, displaced: crate::sys::DisplacedSpare) {
self.group.rollback_pty_spawn(pid, displaced);
}
#[cfg(feature = "process-control")]
pub(crate) fn adopt(&self, child: &Child) -> io::Result<()> {
self.group.adopt(child)
}
#[cfg(feature = "process-control")]
pub(crate) fn adopt_external(&self, pid: u32) -> io::Result<()> {
self.group.adopt_external(pid)
}
pub(crate) fn kill_all(&self) -> io::Result<()> {
self.group.kill_all()
}
#[cfg(feature = "limits")]
pub(crate) fn update_limits(&self, limits: &ResourceLimits) -> io::Result<()> {
if limits.any() {
Err(io::Error::new(
io::ErrorKind::Unsupported,
"resource limits require a cgroup or Job Object; unavailable on this target",
))
} else {
Ok(())
}
}
#[cfg(feature = "limits")]
pub(crate) fn limit_evidence(&self, _capped: crate::limits::CappedAxes) -> LimitEvidence {
LimitEvidence::unknown()
}
#[cfg(feature = "process-control")]
pub(crate) fn signal(&self, sig: Signal) -> io::Result<()> {
self.group.signal(sig.raw())
}
#[cfg(feature = "process-control")]
pub(crate) fn soft_stop_scope(&self) -> crate::SoftStopScope {
crate::SoftStopScope::WholeTree
}
#[cfg(feature = "process-control")]
pub(crate) fn suspend(&self) -> io::Result<()> {
self.group.suspend()
}
#[cfg(feature = "process-control")]
pub(crate) fn resume(&self) -> io::Result<()> {
self.group.resume()
}
#[cfg(feature = "process-control")]
pub(crate) fn members(&self) -> io::Result<Vec<u32>> {
Ok(self
.group
.members()
.into_iter()
.map(|pid| pid as u32)
.collect())
}
#[cfg(feature = "process-control")]
pub(crate) fn members_info(&self) -> io::Result<Vec<MemberInfo>> {
Ok(self.group.members_info())
}
pub(crate) async fn graceful_shutdown(
&self,
signal: i32,
timeout: Duration,
escalate: bool,
) -> io::Result<super::graceful::GracefulOutcome> {
self.group
.graceful_shutdown(signal, timeout, escalate)
.await
}
#[cfg(feature = "stats")]
pub(crate) fn stats(&self) -> io::Result<ProcessGroupStats> {
self.group.stats()
}
pub(crate) fn mechanism(&self) -> Mechanism {
Mechanism::ProcessGroup
}
}
pub(crate) fn detect_mechanism() -> Mechanism {
Mechanism::ProcessGroup
}
#[cfg(feature = "stats")]
pub(crate) fn process_metrics(_pid: u32, _expected: Option<ProcIdentity>) -> ProcMetrics {
ProcMetrics::default()
}
#[cfg(feature = "process-control")]
pub(crate) fn process_info(pid: u32) -> io::Result<Option<MemberInfo>> {
crate::sys::pgroup::process_info(pid)
}
#[cfg(feature = "stats")]
pub(crate) fn process_identity(_pid: u32) -> Option<ProcIdentity> {
None
}