running-process 3.4.0__tar.gz → 3.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {running_process-3.4.0 → running_process-3.4.1}/Cargo.lock +7 -7
- {running_process-3.4.0 → running_process-3.4.1}/Cargo.toml +1 -1
- {running_process-3.4.0 → running_process-3.4.1}/PKG-INFO +1 -1
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-client/Cargo.toml +1 -1
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/Cargo.toml +1 -1
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/lib.rs +181 -6
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/public_symbols.rs +11 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/tests/process_core_test.rs +143 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/Cargo.toml +3 -3
- {running_process-3.4.0 → running_process-3.4.1}/pyproject.toml +1 -1
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/__init__.py +1 -1
- {running_process-3.4.0 → running_process-3.4.1}/LICENSE +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/README.md +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-client/src/client.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-client/src/lib.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-client/src/paths.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-client/src/pipe_session.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-client/src/pty_session.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/console_detect.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/containment.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/originator.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/pty/mod.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/pty/native_pty_process.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/pty/pty_posix.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/pty/pty_windows.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/pty/terminal_input.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/rust_debug.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/spawn.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/spawn_imp_unix.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/spawn_imp_windows.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/tests.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/tests/containment_test.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/tests/fs_adversarial_test.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/tests/originator_test.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/tests/pty_conhost_job_test.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/tests/spawn_test.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-proto/Cargo.toml +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-proto/build.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-proto/proto/daemon.proto +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-proto/src/lib.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/containment.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/daemon_client.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/debug_traces.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/helpers.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/idle_detector.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/lib.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/metrics.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/originator.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/pid_tracking.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/priority.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/process.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/process_tree.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/pty_buffer.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/pty_process.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/public_symbols.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/py_native_process.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/registry.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/signal_bool.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/terminal_input.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/control_churn.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/expect_match.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/idle_detector.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/mod.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/parse_command.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/process_tree.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/pty_buffer.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/pty_process.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/registry.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/signal_bool.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/terminal_input.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/test-watchdog/Cargo.toml +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/crates/test-watchdog/src/lib.rs +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/assets/example.txt +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/cli.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/command_render.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/compat.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/console_encoding.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/daemon.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/dashboard.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/exit_status.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/expect.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/interrupt_handler.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/launch.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/line_iterator.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/output_formatter.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/priority.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/process_utils.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/processor_cli.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/pty/__init__.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/pty/_command.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/pty/_console_io.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/pty/_errors.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/pty/_idle_helpers.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/pty/_idle_state.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/pty/_interactive.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/pty/_process_helpers.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/pty/_pseudo_terminal.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/pty/_terminal_strip.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/pty/_types.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/pty/_wait_input.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/running_process/__init__.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/running_process/_core.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/running_process/_helpers.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/running_process/_iter.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/running_process/_subprocess.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/running_process/_types.py +0 -0
- {running_process-3.4.0 → running_process-3.4.1}/src/running_process/running_process_manager.py +0 -0
|
@@ -210,7 +210,7 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
|
|
210
210
|
|
|
211
211
|
[[package]]
|
|
212
212
|
name = "daemon-trampoline"
|
|
213
|
-
version = "3.4.
|
|
213
|
+
version = "3.4.1"
|
|
214
214
|
dependencies = [
|
|
215
215
|
"libc",
|
|
216
216
|
"serde",
|
|
@@ -1036,7 +1036,7 @@ checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
|
|
1036
1036
|
|
|
1037
1037
|
[[package]]
|
|
1038
1038
|
name = "running-process-client"
|
|
1039
|
-
version = "3.4.
|
|
1039
|
+
version = "3.4.1"
|
|
1040
1040
|
dependencies = [
|
|
1041
1041
|
"dirs",
|
|
1042
1042
|
"interprocess",
|
|
@@ -1047,7 +1047,7 @@ dependencies = [
|
|
|
1047
1047
|
|
|
1048
1048
|
[[package]]
|
|
1049
1049
|
name = "running-process-core"
|
|
1050
|
-
version = "3.4.
|
|
1050
|
+
version = "3.4.1"
|
|
1051
1051
|
dependencies = [
|
|
1052
1052
|
"libc",
|
|
1053
1053
|
"portable-pty",
|
|
@@ -1061,7 +1061,7 @@ dependencies = [
|
|
|
1061
1061
|
|
|
1062
1062
|
[[package]]
|
|
1063
1063
|
name = "running-process-daemon"
|
|
1064
|
-
version = "3.4.
|
|
1064
|
+
version = "3.4.1"
|
|
1065
1065
|
dependencies = [
|
|
1066
1066
|
"bytes",
|
|
1067
1067
|
"clap",
|
|
@@ -1088,7 +1088,7 @@ dependencies = [
|
|
|
1088
1088
|
|
|
1089
1089
|
[[package]]
|
|
1090
1090
|
name = "running-process-proto"
|
|
1091
|
-
version = "3.4.
|
|
1091
|
+
version = "3.4.1"
|
|
1092
1092
|
dependencies = [
|
|
1093
1093
|
"prost",
|
|
1094
1094
|
"prost-build",
|
|
@@ -1098,7 +1098,7 @@ dependencies = [
|
|
|
1098
1098
|
|
|
1099
1099
|
[[package]]
|
|
1100
1100
|
name = "running-process-py"
|
|
1101
|
-
version = "3.4.
|
|
1101
|
+
version = "3.4.1"
|
|
1102
1102
|
dependencies = [
|
|
1103
1103
|
"interprocess",
|
|
1104
1104
|
"libc",
|
|
@@ -1114,7 +1114,7 @@ dependencies = [
|
|
|
1114
1114
|
|
|
1115
1115
|
[[package]]
|
|
1116
1116
|
name = "runpm-cli"
|
|
1117
|
-
version = "3.4.
|
|
1117
|
+
version = "3.4.1"
|
|
1118
1118
|
dependencies = [
|
|
1119
1119
|
"anyhow",
|
|
1120
1120
|
"clap",
|
|
@@ -3,7 +3,7 @@ resolver = "2"
|
|
|
3
3
|
members = ["crates/running-process-core", "crates/running-process-proto", "crates/running-process-client", "crates/running-process-py", "crates/test-watchdog"]
|
|
4
4
|
|
|
5
5
|
[workspace.package]
|
|
6
|
-
version = "3.4.
|
|
6
|
+
version = "3.4.1"
|
|
7
7
|
edition = "2021"
|
|
8
8
|
rust-version = "1.85"
|
|
9
9
|
license = "BSD-3-Clause"
|
|
@@ -9,7 +9,7 @@ homepage.workspace = true
|
|
|
9
9
|
description = "Lightweight synchronous IPC client for the running-process daemon"
|
|
10
10
|
|
|
11
11
|
[dependencies]
|
|
12
|
-
running-process-proto = { path = "../running-process-proto", version = "3.4.
|
|
12
|
+
running-process-proto = { path = "../running-process-proto", version = "3.4.1" }
|
|
13
13
|
prost = "0.14"
|
|
14
14
|
interprocess = "2"
|
|
15
15
|
dirs = "6"
|
|
@@ -17,7 +17,7 @@ libc = "0.2"
|
|
|
17
17
|
portable-pty = "0.9"
|
|
18
18
|
sysinfo = "0.30"
|
|
19
19
|
thiserror = { workspace = true }
|
|
20
|
-
winapi = { version = "0.3", features = ["errhandlingapi", "fileapi", "handleapi", "jobapi2", "namedpipeapi", "processthreadsapi", "winnt", "minwindef", "windef", "winuser", "consoleapi", "processenv", "synchapi", "winbase", "wincon", "tlhelp32"] }
|
|
20
|
+
winapi = { version = "0.3", features = ["errhandlingapi", "fileapi", "handleapi", "ioapiset", "jobapi2", "namedpipeapi", "processthreadsapi", "winnt", "minwindef", "windef", "winuser", "consoleapi", "processenv", "synchapi", "winbase", "wincon", "tlhelp32"] }
|
|
21
21
|
|
|
22
22
|
[dev-dependencies]
|
|
23
23
|
serde_json = "1"
|
|
@@ -40,6 +40,25 @@ macro_rules! rp_rust_debug_scope {
|
|
|
40
40
|
|
|
41
41
|
const CHILD_PID_LOG_PATH_ENV: &str = "RUNNING_PROCESS_CHILD_PID_LOG_PATH";
|
|
42
42
|
|
|
43
|
+
/// Hard cap on how long `kill_impl()` will block on
|
|
44
|
+
/// `wait_for_capture_completion` after the direct child has been
|
|
45
|
+
/// reaped. Override via the `RUNNING_PROCESS_KILL_DRAIN_TIMEOUT_MS`
|
|
46
|
+
/// env var (milliseconds). The default of 2 s gives normal children
|
|
47
|
+
/// time to flush their pipe buffers while preventing indefinite hangs
|
|
48
|
+
/// when a grandchild inherits the pipe and outlives the parent (FastLED
|
|
49
|
+
/// Bug B).
|
|
50
|
+
const DEFAULT_KILL_DRAIN_TIMEOUT: Duration = Duration::from_secs(2);
|
|
51
|
+
const KILL_DRAIN_TIMEOUT_ENV: &str = "RUNNING_PROCESS_KILL_DRAIN_TIMEOUT_MS";
|
|
52
|
+
|
|
53
|
+
fn kill_drain_deadline() -> Instant {
|
|
54
|
+
let timeout = std::env::var(KILL_DRAIN_TIMEOUT_ENV)
|
|
55
|
+
.ok()
|
|
56
|
+
.and_then(|raw| raw.trim().parse::<u64>().ok())
|
|
57
|
+
.map(Duration::from_millis)
|
|
58
|
+
.unwrap_or(DEFAULT_KILL_DRAIN_TIMEOUT);
|
|
59
|
+
Instant::now() + timeout
|
|
60
|
+
}
|
|
61
|
+
|
|
43
62
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
44
63
|
pub enum StreamKind {
|
|
45
64
|
Stdout,
|
|
@@ -168,6 +187,21 @@ struct ChildState {
|
|
|
168
187
|
_job: WindowsJobHandle,
|
|
169
188
|
}
|
|
170
189
|
|
|
190
|
+
/// Parent-side handles for the captured stdout/stderr pipes, kept so
|
|
191
|
+
/// that `kill_impl` can call `CancelIoEx` to interrupt a reader thread
|
|
192
|
+
/// blocked in `read()`. Stored as `usize` because `RawHandle` (a raw
|
|
193
|
+
/// pointer) is not `Send` and we share this via `Arc<Mutex<...>>`.
|
|
194
|
+
///
|
|
195
|
+
/// The reader thread clears its slot (under the mutex) immediately
|
|
196
|
+
/// before dropping its `ChildStd*`, so `kill_impl` never calls
|
|
197
|
+
/// `CancelIoEx` on a closed (and potentially reused) handle.
|
|
198
|
+
#[cfg(windows)]
|
|
199
|
+
#[derive(Default)]
|
|
200
|
+
struct CapturePipeHandles {
|
|
201
|
+
stdout: Option<usize>,
|
|
202
|
+
stderr: Option<usize>,
|
|
203
|
+
}
|
|
204
|
+
|
|
171
205
|
impl SharedState {
|
|
172
206
|
fn new(capture: bool) -> Self {
|
|
173
207
|
let queues = QueueState {
|
|
@@ -187,6 +221,8 @@ pub struct NativeProcess {
|
|
|
187
221
|
config: ProcessConfig,
|
|
188
222
|
child: Arc<Mutex<Option<ChildState>>>,
|
|
189
223
|
shared: Arc<SharedState>,
|
|
224
|
+
#[cfg(windows)]
|
|
225
|
+
capture_pipe_handles: Arc<Mutex<CapturePipeHandles>>,
|
|
190
226
|
}
|
|
191
227
|
|
|
192
228
|
impl NativeProcess {
|
|
@@ -195,6 +231,8 @@ impl NativeProcess {
|
|
|
195
231
|
shared: Arc::new(SharedState::new(config.capture)),
|
|
196
232
|
child: Arc::new(Mutex::new(None)),
|
|
197
233
|
config,
|
|
234
|
+
#[cfg(windows)]
|
|
235
|
+
capture_pipe_handles: Arc::new(Mutex::new(CapturePipeHandles::default())),
|
|
198
236
|
}
|
|
199
237
|
}
|
|
200
238
|
|
|
@@ -234,7 +272,22 @@ impl NativeProcess {
|
|
|
234
272
|
if self.config.capture {
|
|
235
273
|
let stdout = child.stdout.take().expect("stdout pipe missing");
|
|
236
274
|
let stderr = child.stderr.take().expect("stderr pipe missing");
|
|
237
|
-
|
|
275
|
+
#[cfg(windows)]
|
|
276
|
+
{
|
|
277
|
+
use std::os::windows::io::AsRawHandle;
|
|
278
|
+
let mut handles = self
|
|
279
|
+
.capture_pipe_handles
|
|
280
|
+
.lock()
|
|
281
|
+
.expect("capture pipe handles mutex poisoned");
|
|
282
|
+
handles.stdout = Some(stdout.as_raw_handle() as usize);
|
|
283
|
+
handles.stderr = Some(stderr.as_raw_handle() as usize);
|
|
284
|
+
}
|
|
285
|
+
self.spawn_reader(
|
|
286
|
+
stdout,
|
|
287
|
+
StreamKind::Stdout,
|
|
288
|
+
StreamKind::Stdout,
|
|
289
|
+
self.pipe_done_callback(StreamKind::Stdout),
|
|
290
|
+
);
|
|
238
291
|
self.spawn_reader(
|
|
239
292
|
stderr,
|
|
240
293
|
StreamKind::Stderr,
|
|
@@ -242,6 +295,7 @@ impl NativeProcess {
|
|
|
242
295
|
StderrMode::Stdout => StreamKind::Stdout,
|
|
243
296
|
StderrMode::Pipe => StreamKind::Stderr,
|
|
244
297
|
},
|
|
298
|
+
self.pipe_done_callback(StreamKind::Stderr),
|
|
245
299
|
);
|
|
246
300
|
}
|
|
247
301
|
*guard = Some(ChildState {
|
|
@@ -405,6 +459,15 @@ impl NativeProcess {
|
|
|
405
459
|
let status = child.wait().map_err(ProcessError::Io)?;
|
|
406
460
|
self.set_returncode(exit_code(status));
|
|
407
461
|
}
|
|
462
|
+
// On Windows, interrupt any pending blocking `read()` in the
|
|
463
|
+
// per-stream reader threads so they fall out of their loops
|
|
464
|
+
// immediately. This is what makes the grandchild-pipe-orphan
|
|
465
|
+
// case (FastLED Bug B: uv.exe spawns a python.exe grandchild
|
|
466
|
+
// that inherits the pipe and outlives uv) wake up in
|
|
467
|
+
// microseconds instead of waiting for the bounded-drain
|
|
468
|
+
// safety-net deadline below.
|
|
469
|
+
#[cfg(windows)]
|
|
470
|
+
self.cancel_capture_io();
|
|
408
471
|
// Synchronize with the per-stream reader threads so that by the
|
|
409
472
|
// time kill() returns, the capture queues have flipped from
|
|
410
473
|
// "blocked on read" to "closed" and downstream pollers (e.g.
|
|
@@ -412,7 +475,15 @@ impl NativeProcess {
|
|
|
412
475
|
// this, callers that hit a wait()-timeout path see Python code
|
|
413
476
|
// raise TimeoutError, kill the child, then race the reader
|
|
414
477
|
// threads — a 10ms poll loop can miss the EOS flip entirely.
|
|
415
|
-
|
|
478
|
+
//
|
|
479
|
+
// The deadline is the safety-net: on Windows `CancelIoEx`
|
|
480
|
+
// above almost always wakes the readers first; on POSIX, and
|
|
481
|
+
// in any pathological Windows case where `CancelIoEx` doesn't
|
|
482
|
+
// fire, the deadline guarantees `kill()` still returns.
|
|
483
|
+
public_symbols::rp_native_process_wait_for_capture_completion_with_deadline_public(
|
|
484
|
+
self,
|
|
485
|
+
kill_drain_deadline(),
|
|
486
|
+
);
|
|
416
487
|
Ok(())
|
|
417
488
|
}
|
|
418
489
|
|
|
@@ -785,8 +856,9 @@ impl NativeProcess {
|
|
|
785
856
|
} else {
|
|
786
857
|
0
|
|
787
858
|
};
|
|
788
|
-
let flags =
|
|
789
|
-
|
|
859
|
+
let flags = self.config.creationflags.unwrap_or(0)
|
|
860
|
+
| extra
|
|
861
|
+
| windows_priority_flags(self.config.nice);
|
|
790
862
|
if flags != 0 {
|
|
791
863
|
command.creation_flags(flags);
|
|
792
864
|
}
|
|
@@ -818,8 +890,13 @@ impl NativeProcess {
|
|
|
818
890
|
command
|
|
819
891
|
}
|
|
820
892
|
|
|
821
|
-
fn spawn_reader<R>(
|
|
822
|
-
|
|
893
|
+
fn spawn_reader<R>(
|
|
894
|
+
&self,
|
|
895
|
+
pipe: R,
|
|
896
|
+
source_stream: StreamKind,
|
|
897
|
+
visible_stream: StreamKind,
|
|
898
|
+
on_pipe_done: Box<dyn FnOnce() + Send>,
|
|
899
|
+
) where
|
|
823
900
|
R: Read + Send + 'static,
|
|
824
901
|
{
|
|
825
902
|
let shared = Arc::clone(&self.shared);
|
|
@@ -843,6 +920,13 @@ impl NativeProcess {
|
|
|
843
920
|
emit_lines(&shared, visible_stream, vec![std::mem::take(&mut pending)]);
|
|
844
921
|
}
|
|
845
922
|
|
|
923
|
+
// Clear the parent-side pipe-handle slot under its mutex
|
|
924
|
+
// before dropping the reader. After this returns,
|
|
925
|
+
// `kill_impl` can no longer try to `CancelIoEx` on us, so
|
|
926
|
+
// it's safe for `reader`'s drop to close the HANDLE.
|
|
927
|
+
on_pipe_done();
|
|
928
|
+
drop(reader);
|
|
929
|
+
|
|
846
930
|
let mut guard = shared.queues.lock().expect("queue mutex poisoned");
|
|
847
931
|
match source_stream {
|
|
848
932
|
StreamKind::Stdout => guard.stdout_closed = true,
|
|
@@ -852,6 +936,57 @@ impl NativeProcess {
|
|
|
852
936
|
});
|
|
853
937
|
}
|
|
854
938
|
|
|
939
|
+
#[cfg(windows)]
|
|
940
|
+
fn pipe_done_callback(&self, stream: StreamKind) -> Box<dyn FnOnce() + Send> {
|
|
941
|
+
let handles = Arc::clone(&self.capture_pipe_handles);
|
|
942
|
+
Box::new(move || {
|
|
943
|
+
let mut guard = handles
|
|
944
|
+
.lock()
|
|
945
|
+
.expect("capture pipe handles mutex poisoned");
|
|
946
|
+
match stream {
|
|
947
|
+
StreamKind::Stdout => guard.stdout = None,
|
|
948
|
+
StreamKind::Stderr => guard.stderr = None,
|
|
949
|
+
}
|
|
950
|
+
})
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
#[cfg(not(windows))]
|
|
954
|
+
fn pipe_done_callback(&self, _stream: StreamKind) -> Box<dyn FnOnce() + Send> {
|
|
955
|
+
Box::new(|| {})
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
/// Cancel any pending blocking `read()` on the parent-side capture
|
|
959
|
+
/// pipes so the reader threads' `read()` calls return
|
|
960
|
+
/// `ERROR_OPERATION_ABORTED` immediately. Used by `kill_impl` to
|
|
961
|
+
/// break the grandchild-orphan deadlock without waiting on
|
|
962
|
+
/// `wait_for_capture_completion_with_deadline`'s safety-net.
|
|
963
|
+
#[cfg(windows)]
|
|
964
|
+
fn cancel_capture_io(&self) {
|
|
965
|
+
crate::rp_rust_debug_scope!("running_process_core::NativeProcess::cancel_capture_io");
|
|
966
|
+
use winapi::shared::ntdef::HANDLE;
|
|
967
|
+
use winapi::um::ioapiset::CancelIoEx;
|
|
968
|
+
let guard = self
|
|
969
|
+
.capture_pipe_handles
|
|
970
|
+
.lock()
|
|
971
|
+
.expect("capture pipe handles mutex poisoned");
|
|
972
|
+
if let Some(h) = guard.stdout {
|
|
973
|
+
// SAFETY: the slot is `Some` only while the owning reader
|
|
974
|
+
// thread still holds the `ChildStdout`, so the HANDLE is
|
|
975
|
+
// valid for the duration of this call. The reader is
|
|
976
|
+
// blocked in `lock()` on the same mutex if it's racing us
|
|
977
|
+
// toward exit, so it cannot drop the pipe and close the
|
|
978
|
+
// HANDLE until we return.
|
|
979
|
+
unsafe {
|
|
980
|
+
CancelIoEx(h as HANDLE, std::ptr::null_mut());
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
if let Some(h) = guard.stderr {
|
|
984
|
+
unsafe {
|
|
985
|
+
CancelIoEx(h as HANDLE, std::ptr::null_mut());
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
|
|
855
990
|
fn set_returncode(&self, code: i32) {
|
|
856
991
|
self.shared.returncode.store(code as i64, Ordering::Release);
|
|
857
992
|
self.shared.condvar.notify_all();
|
|
@@ -874,6 +1009,46 @@ impl NativeProcess {
|
|
|
874
1009
|
.expect("queue mutex poisoned");
|
|
875
1010
|
}
|
|
876
1011
|
}
|
|
1012
|
+
|
|
1013
|
+
/// Like `wait_for_capture_completion_impl` but bounded by `deadline`.
|
|
1014
|
+
/// Returns `true` if the reader threads flipped both closed flags on
|
|
1015
|
+
/// their own, `false` if the deadline elapsed first. On timeout the
|
|
1016
|
+
/// closed flags are force-set (and waiters notified) so downstream
|
|
1017
|
+
/// pollers stop seeing `Timeout` and start seeing `Eof`. A reader
|
|
1018
|
+
/// thread that eventually unblocks after the OS releases the pipe
|
|
1019
|
+
/// will assign `closed = true` again, which is a harmless no-op.
|
|
1020
|
+
fn wait_for_capture_completion_with_deadline_impl(&self, deadline: Instant) -> bool {
|
|
1021
|
+
crate::rp_rust_debug_scope!(
|
|
1022
|
+
"running_process_core::NativeProcess::wait_for_capture_completion_with_deadline"
|
|
1023
|
+
);
|
|
1024
|
+
if !self.config.capture {
|
|
1025
|
+
return true;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
let mut guard = self.shared.queues.lock().expect("queue mutex poisoned");
|
|
1029
|
+
while !(guard.stdout_closed && guard.stderr_closed) {
|
|
1030
|
+
let now = Instant::now();
|
|
1031
|
+
if now >= deadline {
|
|
1032
|
+
guard.stdout_closed = true;
|
|
1033
|
+
guard.stderr_closed = true;
|
|
1034
|
+
self.shared.condvar.notify_all();
|
|
1035
|
+
return false;
|
|
1036
|
+
}
|
|
1037
|
+
let (next_guard, result) = self
|
|
1038
|
+
.shared
|
|
1039
|
+
.condvar
|
|
1040
|
+
.wait_timeout(guard, deadline - now)
|
|
1041
|
+
.expect("queue mutex poisoned");
|
|
1042
|
+
guard = next_guard;
|
|
1043
|
+
if result.timed_out() && !(guard.stdout_closed && guard.stderr_closed) {
|
|
1044
|
+
guard.stdout_closed = true;
|
|
1045
|
+
guard.stderr_closed = true;
|
|
1046
|
+
self.shared.condvar.notify_all();
|
|
1047
|
+
return false;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
true
|
|
1051
|
+
}
|
|
877
1052
|
}
|
|
878
1053
|
|
|
879
1054
|
#[cfg(unix)]
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/public_symbols.rs
RENAMED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#![allow(improper_ctypes_definitions)]
|
|
2
2
|
|
|
3
|
+
use std::time::Instant;
|
|
4
|
+
|
|
3
5
|
use super::*;
|
|
4
6
|
|
|
5
7
|
#[unsafe(no_mangle)]
|
|
@@ -50,6 +52,15 @@ pub extern "C" fn rp_native_process_wait_for_capture_completion_public(process:
|
|
|
50
52
|
process.wait_for_capture_completion_impl();
|
|
51
53
|
}
|
|
52
54
|
|
|
55
|
+
#[unsafe(no_mangle)]
|
|
56
|
+
#[inline(never)]
|
|
57
|
+
pub extern "C" fn rp_native_process_wait_for_capture_completion_with_deadline_public(
|
|
58
|
+
process: &NativeProcess,
|
|
59
|
+
deadline: Instant,
|
|
60
|
+
) -> bool {
|
|
61
|
+
process.wait_for_capture_completion_with_deadline_impl(deadline)
|
|
62
|
+
}
|
|
63
|
+
|
|
53
64
|
#[cfg(windows)]
|
|
54
65
|
#[unsafe(no_mangle)]
|
|
55
66
|
#[inline(never)]
|
|
@@ -648,6 +648,149 @@ fn terminate_kills_running_process() {
|
|
|
648
648
|
process.terminate().unwrap();
|
|
649
649
|
}
|
|
650
650
|
|
|
651
|
+
/// FastLED Bug B follow-up: on Windows, `kill()` must wake the
|
|
652
|
+
/// reader threads via `CancelIoEx` *immediately* even when a
|
|
653
|
+
/// grandchild keeps the captured pipe open. This is what the
|
|
654
|
+
/// `cancel_capture_io()` call in `kill_impl` provides — without it,
|
|
655
|
+
/// kill() would wait for the full `RUNNING_PROCESS_KILL_DRAIN_TIMEOUT_MS`
|
|
656
|
+
/// safety-net deadline before returning. The test sets that deadline
|
|
657
|
+
/// to 5000 ms and asserts kill() returns in under 1 s, proving the
|
|
658
|
+
/// CancelIoEx fast path is wired up.
|
|
659
|
+
#[cfg(windows)]
|
|
660
|
+
#[test]
|
|
661
|
+
fn kill_cancels_capture_io_when_grandchild_orphans_pipe() {
|
|
662
|
+
let script = "\
|
|
663
|
+
import os, subprocess, sys, time;\
|
|
664
|
+
print('PARENT_PID=' + str(os.getpid()), flush=True);\
|
|
665
|
+
gc = subprocess.Popen([sys.executable, '-c', 'import time; time.sleep(60)']);\
|
|
666
|
+
print('GRANDCHILD_PID=' + str(gc.pid), flush=True);\
|
|
667
|
+
time.sleep(60)";
|
|
668
|
+
|
|
669
|
+
let process = NativeProcess::new(config(
|
|
670
|
+
CommandSpec::Argv(vec!["python".into(), "-c".into(), script.into()]),
|
|
671
|
+
true,
|
|
672
|
+
StdinMode::Inherit,
|
|
673
|
+
None,
|
|
674
|
+
));
|
|
675
|
+
|
|
676
|
+
process.start().unwrap();
|
|
677
|
+
|
|
678
|
+
let mut grandchild_pid: Option<u32> = None;
|
|
679
|
+
let deadline = Instant::now() + Duration::from_secs(10);
|
|
680
|
+
while Instant::now() < deadline {
|
|
681
|
+
match process.read_combined(Some(Duration::from_millis(200))) {
|
|
682
|
+
ReadStatus::Line(event) => {
|
|
683
|
+
let line = String::from_utf8_lossy(&event.line).into_owned();
|
|
684
|
+
if let Some(rest) = line.strip_prefix("GRANDCHILD_PID=") {
|
|
685
|
+
grandchild_pid = rest.trim().parse::<u32>().ok();
|
|
686
|
+
break;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
ReadStatus::Timeout => continue,
|
|
690
|
+
ReadStatus::Eof => panic!("parent exited before announcing grandchild"),
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
let grandchild_pid = grandchild_pid.expect("did not observe GRANDCHILD_PID line");
|
|
694
|
+
|
|
695
|
+
// Crank the safety-net drain deadline way up so the only way
|
|
696
|
+
// kill() can return fast is via the CancelIoEx fast path.
|
|
697
|
+
let prior = env::var_os("RUNNING_PROCESS_KILL_DRAIN_TIMEOUT_MS");
|
|
698
|
+
env::set_var("RUNNING_PROCESS_KILL_DRAIN_TIMEOUT_MS", "5000");
|
|
699
|
+
|
|
700
|
+
let kill_start = Instant::now();
|
|
701
|
+
let kill_result = process.kill();
|
|
702
|
+
let kill_elapsed = kill_start.elapsed();
|
|
703
|
+
|
|
704
|
+
match prior {
|
|
705
|
+
Some(v) => env::set_var("RUNNING_PROCESS_KILL_DRAIN_TIMEOUT_MS", v),
|
|
706
|
+
None => env::remove_var("RUNNING_PROCESS_KILL_DRAIN_TIMEOUT_MS"),
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
kill_result.expect("kill() returned an error");
|
|
710
|
+
assert!(
|
|
711
|
+
kill_elapsed < Duration::from_secs(1),
|
|
712
|
+
"kill() took {kill_elapsed:?} with 5 s safety-net deadline; \
|
|
713
|
+
CancelIoEx fast path is not interrupting the reader thread",
|
|
714
|
+
);
|
|
715
|
+
|
|
716
|
+
let _ = Command::new("taskkill")
|
|
717
|
+
.args(["/F", "/T", "/PID", &grandchild_pid.to_string()])
|
|
718
|
+
.stdout(Stdio::null())
|
|
719
|
+
.stderr(Stdio::null())
|
|
720
|
+
.status();
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/// FastLED Bug B regression: when a grandchild inherits the captured
|
|
724
|
+
/// stdout pipe and outlives the direct child, `kill()` must still
|
|
725
|
+
/// return promptly instead of blocking forever in
|
|
726
|
+
/// `wait_for_capture_completion`. Mirrors the `uv run python ...`
|
|
727
|
+
/// shape, where uv exits while a python grandchild keeps the pipe open.
|
|
728
|
+
#[test]
|
|
729
|
+
fn kill_returns_when_grandchild_inherits_stdout_pipe() {
|
|
730
|
+
// Parent: print its own PID, spawn a grandchild python that sleeps
|
|
731
|
+
// 60 s with inherited stdout, then itself sleep 60 s. We kill the
|
|
732
|
+
// parent before either sleep elapses; the grandchild stays alive
|
|
733
|
+
// (and thus the pipe stays open) for the duration of the test.
|
|
734
|
+
let script = "\
|
|
735
|
+
import os, subprocess, sys, time;\
|
|
736
|
+
print('PARENT_PID=' + str(os.getpid()), flush=True);\
|
|
737
|
+
gc = subprocess.Popen([sys.executable, '-c', 'import time; time.sleep(60)']);\
|
|
738
|
+
print('GRANDCHILD_PID=' + str(gc.pid), flush=True);\
|
|
739
|
+
time.sleep(60)";
|
|
740
|
+
|
|
741
|
+
let process = NativeProcess::new(config(
|
|
742
|
+
CommandSpec::Argv(vec!["python".into(), "-c".into(), script.into()]),
|
|
743
|
+
true,
|
|
744
|
+
StdinMode::Inherit,
|
|
745
|
+
None,
|
|
746
|
+
));
|
|
747
|
+
|
|
748
|
+
process.start().unwrap();
|
|
749
|
+
|
|
750
|
+
// Wait for the parent to spawn the grandchild and announce both PIDs.
|
|
751
|
+
let mut grandchild_pid: Option<u32> = None;
|
|
752
|
+
let deadline = Instant::now() + Duration::from_secs(10);
|
|
753
|
+
while Instant::now() < deadline {
|
|
754
|
+
match process.read_combined(Some(Duration::from_millis(200))) {
|
|
755
|
+
ReadStatus::Line(event) => {
|
|
756
|
+
let line = String::from_utf8_lossy(&event.line).into_owned();
|
|
757
|
+
if let Some(rest) = line.strip_prefix("GRANDCHILD_PID=") {
|
|
758
|
+
grandchild_pid = rest.trim().parse::<u32>().ok();
|
|
759
|
+
break;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
ReadStatus::Timeout => continue,
|
|
763
|
+
ReadStatus::Eof => panic!("parent exited before announcing grandchild"),
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
let grandchild_pid = grandchild_pid.expect("did not observe GRANDCHILD_PID line");
|
|
767
|
+
|
|
768
|
+
// The grandchild now holds the stdout pipe open. kill() on the
|
|
769
|
+
// parent reaps the parent but the reader thread is still blocked
|
|
770
|
+
// on read(); without the bounded wait this hangs forever.
|
|
771
|
+
let kill_start = Instant::now();
|
|
772
|
+
process.kill().expect("kill() returned an error");
|
|
773
|
+
let kill_elapsed = kill_start.elapsed();
|
|
774
|
+
assert!(
|
|
775
|
+
kill_elapsed < Duration::from_secs(5),
|
|
776
|
+
"kill() blocked for {kill_elapsed:?}; expected bounded return after grandchild orphan",
|
|
777
|
+
);
|
|
778
|
+
|
|
779
|
+
// Cleanup: terminate the lingering grandchild so it doesn't leak.
|
|
780
|
+
#[cfg(windows)]
|
|
781
|
+
{
|
|
782
|
+
let _ = Command::new("taskkill")
|
|
783
|
+
.args(["/F", "/T", "/PID", &grandchild_pid.to_string()])
|
|
784
|
+
.stdout(Stdio::null())
|
|
785
|
+
.stderr(Stdio::null())
|
|
786
|
+
.status();
|
|
787
|
+
}
|
|
788
|
+
#[cfg(not(windows))]
|
|
789
|
+
unsafe {
|
|
790
|
+
libc::kill(grandchild_pid as i32, libc::SIGKILL);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
651
794
|
// ── pid() ──
|
|
652
795
|
|
|
653
796
|
#[test]
|
|
@@ -16,10 +16,10 @@ crate-type = ["cdylib", "lib"]
|
|
|
16
16
|
libc = "0.2"
|
|
17
17
|
pyo3 = { workspace = true }
|
|
18
18
|
regex = "1"
|
|
19
|
-
running-process-core = { path = "../running-process-core", version = "3.4.
|
|
19
|
+
running-process-core = { path = "../running-process-core", version = "3.4.1", features = ["originator-scan"] }
|
|
20
20
|
sysinfo = "0.30"
|
|
21
21
|
winapi = { version = "0.3", features = ["consoleapi", "handleapi", "jobapi2", "processenv", "processthreadsapi", "synchapi", "winbase", "wincon", "winnt", "winuser"] }
|
|
22
|
-
running-process-proto = { path = "../running-process-proto", version = "3.4.
|
|
23
|
-
running-process-client = { path = "../running-process-client", version = "3.4.
|
|
22
|
+
running-process-proto = { path = "../running-process-proto", version = "3.4.1" }
|
|
23
|
+
running-process-client = { path = "../running-process-client", version = "3.4.1" }
|
|
24
24
|
prost = "0.14"
|
|
25
25
|
interprocess = "2"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-client/src/pipe_session.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-client/src/pty_session.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/console_detect.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/containment.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/originator.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/pty/pty_posix.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/pty/pty_windows.rs
RENAMED
|
File without changes
|
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/rust_debug.rs
RENAMED
|
File without changes
|
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/spawn_imp_unix.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/src/spawn_imp_windows.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/tests/originator_test.rs
RENAMED
|
File without changes
|
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-core/tests/spawn_test.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-proto/proto/daemon.proto
RENAMED
|
File without changes
|
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/containment.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/daemon_client.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/debug_traces.rs
RENAMED
|
File without changes
|
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/idle_detector.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/pid_tracking.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/process_tree.rs
RENAMED
|
File without changes
|
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/pty_process.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/public_symbols.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/py_native_process.rs
RENAMED
|
File without changes
|
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/signal_bool.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/terminal_input.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/control_churn.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/expect_match.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/idle_detector.rs
RENAMED
|
File without changes
|
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/parse_command.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/process_tree.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/pty_buffer.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/pty_process.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/registry.rs
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/crates/running-process-py/src/tests/signal_bool.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/src/running_process/running_process/__init__.py
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/src/running_process/running_process/_core.py
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/src/running_process/running_process/_helpers.py
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/src/running_process/running_process/_iter.py
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/src/running_process/running_process/_subprocess.py
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/src/running_process/running_process/_types.py
RENAMED
|
File without changes
|
{running_process-3.4.0 → running_process-3.4.1}/src/running_process/running_process_manager.py
RENAMED
|
File without changes
|