Skip to main content

running_process_platform_internal/platform/
process.rs

1//! Process spawning, containment, inspection, termination, and stdio.
2
3pub use crate::{
4    PlatformChild, PlatformEmergencySignal, PlatformLifecycle, PlatformOutput, PlatformStdin,
5    SpawnSpec, StreamMode,
6};
7
8pub use crate::platform_imp::{
9    cancel_capture_reader, canonical_environment_pairs, capture_reader_done, compat_shell_command,
10    configure_native_command, configure_sync_contained_command, configure_sync_daemon_command,
11    configure_trampoline_command, enable_descendant_subreaper, exit_code, monitor_console_windows,
12    parent_has_console, prepare_capture_reader, process_snapshot, process_snapshot_for_pid,
13    set_process_name, shell_command, soft_terminate_process_group, spawn_sync, spawn_sync_daemon,
14    sync_child_native_handle, trampoline_exit_code, unix_mark_extra_fds_close_on_exec,
15    CaptureCancellation,
16};
17
18/// Identifies one captured child output stream.
19#[derive(Clone, Copy)]
20pub enum CaptureStream {
21    Stdout,
22    Stderr,
23}
24
25/// Metadata about one visible window observed by console-popup monitoring.
26#[derive(Debug, Clone)]
27pub struct ConsoleWindowInfo {
28    pub pid: u32,
29    pub title: String,
30    pub hwnd: u64,
31}
32
33/// A platform-owned identity record used when observing a process tree.
34/// The timestamp fields are opaque host-native creation-time components and
35/// must only be compared for equality.
36#[derive(Clone, Copy, Debug, Eq, PartialEq)]
37pub struct ProcessSnapshot {
38    pub pid: u32,
39    pub parent_pid: u32,
40    pub start_time_a: u64,
41    pub start_time_b: u64,
42}
43
44/// Environment base selected by the shared caller for a synchronous spawn.
45///
46/// Explicit `Command::env` additions and removals remain on the command and
47/// are applied after this base by the selected platform implementation.
48#[derive(Clone, Debug, Eq, PartialEq)]
49pub enum SyncEnvironment {
50    /// Start with the spawning process's ambient environment.
51    Inherit,
52    /// Start with this complete, caller-assembled base environment.
53    Explicit(Vec<(std::ffi::OsString, std::ffi::OsString)>),
54}
55
56/// Caller-supplied stdio bindings for a contained synchronous child.
57///
58/// Each stream is independently configured. `drain_timeout` bounds how long
59/// wrapper-owned pipe ends remain open after the child exits; `None` leaves
60/// pipe closure entirely to the caller. `show_console` only affects Windows.
61pub struct SpawnStdio<'a> {
62    /// Child standard input source.
63    pub stdin: StdioSource<'a>,
64    /// Child standard output destination.
65    pub stdout: StdioSource<'a>,
66    /// Child standard error destination.
67    pub stderr: StdioSource<'a>,
68    /// Maximum post-exit pipe drain interval.
69    pub drain_timeout: Option<std::time::Duration>,
70    /// Whether a Windows child may inherit or allocate a visible console.
71    pub show_console: bool,
72}
73
74impl Default for SpawnStdio<'_> {
75    fn default() -> Self {
76        Self {
77            stdin: StdioSource::Null,
78            stdout: StdioSource::Parent,
79            stderr: StdioSource::Parent,
80            drain_timeout: Some(std::time::Duration::from_secs(2)),
81            show_console: false,
82        }
83    }
84}
85
86/// Caller-supplied output bindings for a detached synchronous child.
87///
88/// Detached children may write only to the platform null device or to a
89/// caller-owned file. Parent stdio and anonymous pipes are intentionally not
90/// available because either can retain or depend on the launching process.
91pub struct DaemonStdio<'a> {
92    /// Child standard output destination.
93    pub stdout: DaemonStdioSource<'a>,
94    /// Child standard error destination.
95    pub stderr: DaemonStdioSource<'a>,
96}
97
98impl Default for DaemonStdio<'_> {
99    fn default() -> Self {
100        Self {
101            stdout: DaemonStdioSource::Null,
102            stderr: DaemonStdioSource::Null,
103        }
104    }
105}
106
107/// Output destination accepted by the detached-child path.
108pub enum DaemonStdioSource<'a> {
109    /// Route output to the platform null device.
110    Null,
111    /// Duplicate a caller-owned file into the child.
112    File(&'a std::fs::File),
113}
114
115/// Standard-stream source or destination for a contained child.
116pub enum StdioSource<'a> {
117    /// Route the stream to the platform null device.
118    Null,
119    /// Inherit the matching stream from the parent process.
120    Parent,
121    /// Duplicate a caller-owned file into the child.
122    File(&'a std::fs::File),
123    /// Create and return an anonymous parent/child pipe pair.
124    Pipe,
125}
126
127/// Handle for a detached child that is not terminated when dropped.
128pub struct DaemonChild {
129    pub(crate) pid: u32,
130    pub(crate) inner: Box<dyn DaemonChildControl>,
131}
132
133pub(crate) trait DaemonChildControl:
134    Send + Sync + std::panic::UnwindSafe + std::panic::RefUnwindSafe
135{
136    fn kill(&mut self) -> std::io::Result<()>;
137    fn wait(&mut self) -> std::io::Result<i32>;
138    fn try_wait(&mut self) -> std::io::Result<Option<i32>>;
139}
140
141impl DaemonChild {
142    /// Return the operating-system process identifier.
143    pub fn id(&self) -> u32 {
144        self.pid
145    }
146
147    /// Terminate the child process.
148    pub fn kill(&mut self) -> std::io::Result<()> {
149        self.inner.kill()
150    }
151
152    /// Wait for the child and return its numeric exit code.
153    pub fn wait(&mut self) -> std::io::Result<i32> {
154        self.inner.wait()
155    }
156
157    /// Return the exit code if the child has finished without blocking.
158    pub fn try_wait(&mut self) -> std::io::Result<Option<i32>> {
159        self.inner.try_wait()
160    }
161}
162
163/// Handle and optional parent pipe ends for a contained child.
164///
165/// Dropping this value shuts down the contained process group.
166pub struct SpawnedChild {
167    /// Writable parent end when standard input was configured as a pipe.
168    pub stdin: Option<std::process::ChildStdin>,
169    /// Readable parent end when standard output was configured as a pipe.
170    pub stdout: Option<std::process::ChildStdout>,
171    /// Readable parent end when standard error was configured as a pipe.
172    pub stderr: Option<std::process::ChildStderr>,
173    pub(crate) pid: u32,
174    pub(crate) inner: Box<dyn SpawnedChildControl>,
175}
176
177pub(crate) trait SpawnedChildControl:
178    Send + Sync + std::panic::UnwindSafe + std::panic::RefUnwindSafe
179{
180    fn kill(&mut self) -> std::io::Result<()>;
181    fn wait(&mut self) -> std::io::Result<i32>;
182    fn try_wait(&mut self) -> std::io::Result<Option<i32>>;
183    fn shutdown(&mut self);
184}
185
186impl SpawnedChild {
187    /// Return the operating-system process identifier.
188    pub fn id(&self) -> u32 {
189        self.pid
190    }
191
192    /// Forcibly terminate the child on a best-effort basis.
193    pub fn kill(&mut self) -> std::io::Result<()> {
194        self.inner.kill()
195    }
196
197    /// Wait for the child and return its numeric exit code.
198    pub fn wait(&mut self) -> std::io::Result<i32> {
199        self.inner.wait()
200    }
201
202    /// Return the exit code if the child has finished without blocking.
203    pub fn try_wait(&mut self) -> std::io::Result<Option<i32>> {
204        self.inner.try_wait()
205    }
206}
207
208impl Drop for SpawnedChild {
209    fn drop(&mut self) {
210        self.inner.shutdown();
211    }
212}
213
214#[derive(Clone, Copy)]
215pub enum ObserverScope {
216    SystemWide,
217    LaunchedProcessTree,
218}
219#[derive(Clone, Copy)]
220pub enum ObserverCategory {
221    File,
222    Network,
223    Process,
224}
225#[derive(Clone, Copy)]
226pub enum ObserverSupport {
227    Supported,
228    Partial,
229    Unavailable,
230}
231#[derive(Clone, Copy)]
232pub struct ObserverBackend {
233    pub support: ObserverSupport,
234    pub backend: &'static str,
235    pub reason: &'static str,
236}
237pub use crate::platform_imp::observer_backend;
238pub use crate::platform_imp::read_process_cmdline;
239pub use crate::platform_imp::read_process_file_handles;
240
241/// Platform-neutral Unix signal selectors used by the compatibility facade.
242#[derive(Debug, Clone, Copy, PartialEq, Eq)]
243pub enum UnixSignalKind {
244    Interrupt,
245    Terminate,
246    Kill,
247}
248
249pub use crate::platform_imp::{
250    unix_set_priority, unix_signal_process, unix_signal_process_group, unix_signal_raw,
251};
252
253pub use crate::platform_imp::kill_tree;