pub struct Running<'obs> { /* private fields */ }Expand description
A running sandbox.
Returned by Cage::spawn and Cage::spawn_with once the command is
executing. The handle owns the caller side of the sandbox’s channels:
waiting pumps captured output to the observer and collects the command’s
exit status, terminate requests a graceful stop,
and kill forcibly tears the sandbox down.
Waiting is fused: once the outcome is known, every further wait returns it without blocking.
Dropping the handle without waiting neither kills the sandbox (unless
stop_with_caller is set, whose tie the drop severs) nor collects its
outcome; without a PID namespace the supervisor process then remains a
zombie child process of the caller until the caller exits. Prefer waiting —
including after a kill.
The escalation recipe, for callers that need a bounded stop:
let mut running = cage.spawn()?;
let status = match running.wait_deadline(soft)? {
Some(status) => status,
None => {
running.terminate()?; // SIGTERM: a chance to exit cleanly
match running.wait_deadline(hard)? {
Some(status) => status,
None => {
running.kill()?; // SIGKILL: tear the sandbox down
running.wait()?
}
}
}
};Implementations§
Source§impl<'obs> Running<'obs>
impl<'obs> Running<'obs>
Sourcepub fn pid(&self) -> u32
pub fn pid(&self) -> u32
The host process id of the sandbox supervisor — the process this handle anchors on: the namespace init, or the command process itself without a PID namespace. Not the launch stage, which built the namespaces and, with a PID namespace, has already exited.
Informational — for signaling, use kill and
terminate, which cannot hit a recycled pid.
Sourcepub fn wait(&mut self) -> Result<ExitStatus, Error>
pub fn wait(&mut self) -> Result<ExitStatus, Error>
Waits for the command to terminate, pumping captured output to the observer, and returns its exit status.
Like Cage::run, a non-zero exit is data, not an error. An error
means the library failed to collect the outcome.
When output is captured, the wait completes once the command’s
outcome is known and both captured streams have reached end-of-file.
Under the default PID namespace, teardown at command exit closes
the streams promptly. With pid_namespace(false), a descendant
that outlives the command holds the streams open, and an unbounded
wait blocks until the last holder closes them; a caller whose
command may leave such descendants behind should prefer
wait_deadline or
wait_timeout.
Sourcepub fn wait_deadline(
&mut self,
deadline: Instant,
) -> Result<Option<ExitStatus>, Error>
pub fn wait_deadline( &mut self, deadline: Instant, ) -> Result<Option<ExitStatus>, Error>
Waits until the command terminates or the deadline passes.
Returns Ok(None) when the deadline passes first; the command keeps
running, output produced before the deadline has been delivered, and
the wait can be resumed. The deadline does not kill anything —
escalation is the caller’s, per the recipe above.
Sourcepub fn wait_timeout(
&mut self,
timeout: Duration,
) -> Result<Option<ExitStatus>, Error>
pub fn wait_timeout( &mut self, timeout: Duration, ) -> Result<Option<ExitStatus>, Error>
wait_deadline with a relative timeout.
Sourcepub fn terminate(&mut self) -> Result<(), Error>
pub fn terminate(&mut self) -> Result<(), Error>
Requests graceful termination: SIGTERM to the command.
The signal is deliverable and trappable, docker-stop style; a
command may clean up and exit, or may ignore it. Follow with a
deadline and kill for a bounded stop. Requesting
termination of a sandbox that has already exited is not an error.
Sourcepub fn kill(&mut self) -> Result<(), Error>
pub fn kill(&mut self) -> Result<(), Error>
Kills the sandbox: SIGKILL to the supervisor.
With a PID namespace this kills its init, and the kernel then kills every process in the namespace — nothing survives. Without one, only the command process itself is killed; descendants it spawned are beyond the library’s reach.
The kill is delivered through a pidfd and cannot hit a recycled pid.
Killing a sandbox that has already exited is not an error. After a
kill, wait still pumps the output produced before
the kill and then reports the outcome.
The killed outcome is reported as signaled(SIGKILL) only once the
signal is known delivered; the flag that carries that fact is set after
the signal so a failed signal cannot fabricate a killed outcome. When a
KillHandle on another thread issues the kill while this thread is
waiting, that ordering leaves a narrow window in which the waiter can
observe the supervisor’s death before the flag is set and report
Error::SupervisorLost instead of signaled(SIGKILL). The kill still
took effect; only the reported form differs, and only for a
cross-thread kill racing the wait. A same-thread kill (this method
before a subsequent wait) is not affected.
Sourcepub fn kill_handle(&self) -> Result<KillHandle, Error>
pub fn kill_handle(&self) -> Result<KillHandle, Error>
Returns a handle that can terminate or kill the sandbox from another thread, while this handle blocks in a wait.
Trait Implementations§
Auto Trait Implementations§
impl<'obs> !RefUnwindSafe for Running<'obs>
impl<'obs> !Send for Running<'obs>
impl<'obs> !Sync for Running<'obs>
impl<'obs> !UnwindSafe for Running<'obs>
impl<'obs> Freeze for Running<'obs>
impl<'obs> Unpin for Running<'obs>
impl<'obs> UnsafeUnpin for Running<'obs>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.