Skip to content

Commit 558ea91

Browse files
use ctrl-break for process groups
1 parent af109f2 commit 558ea91

File tree

5 files changed

+58
-9
lines changed

5 files changed

+58
-9
lines changed

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/icp-cli/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,17 @@ assert_cmd = "2"
6565
camino-tempfile = "1"
6666
indoc.workspace = true
6767
icp = { workspace = true }
68-
nix = { version = "0.30.1", features = ["process", "signal"] }
6968
predicates = "3"
7069
rand.workspace = true
70+
send_ctrlc = "0.6"
7171
serde_yaml.workspace = true
7272
serial_test = { version = "3.2.0", features = ["file_locks"] }
7373
test-tag = "0.1"
7474
uuid.workspace = true
7575

76+
[target.'cfg(unix)'.dev-dependencies]
77+
nix = { version = "0.30.1", features = ["process", "signal"] }
78+
7679
[lints]
7780
workspace = true
7881

crates/icp-cli/tests/common/context.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,8 @@ impl TestContext {
255255
}
256256
let watcher =
257257
wait_for_launcher_status(&launcher_dir).expect("Failed to watch launcher status");
258-
let child = cmd.spawn().expect("failed to spawn launcher");
258+
let guard = ChildGuard::spawn(&mut cmd).expect("Failed to spawn network launcher");
259+
let child = &guard.child;
259260
let launcher_pid = child.id();
260261

261262
// Wait for port file using the function from icp-network
@@ -315,8 +316,7 @@ impl TestContext {
315316
.unwrap(),
316317
)
317318
.expect("Gateway URL should not be already initialized");
318-
// Wrap child in ChildGuard
319-
ChildGuard { child }
319+
guard
320320
}
321321

322322
pub(crate) fn ping_until_healthy(&self, project_dir: &Path, name: &str) {

crates/icp-cli/tests/common/mod.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
#![allow(dead_code)]
22

3-
use std::process::{Child, Command};
3+
use std::process::Command;
44

55
use httptest::{Expectation, Server, matchers::*, responders::*};
66

77
pub(crate) mod clients;
88
mod context;
99

1010
pub(crate) use context::TestContext;
11+
use send_ctrlc::{InterruptibleChild, InterruptibleCommand};
1112

1213
#[cfg(unix)]
1314
pub(crate) const PATH_SEPARATOR: &str = ":";
@@ -79,7 +80,7 @@ pub(crate) struct TestNetwork {
7980
}
8081

8182
pub(crate) struct ChildGuard {
82-
child: Child,
83+
child: InterruptibleChild,
8384
}
8485

8586
impl ChildGuard {
@@ -89,7 +90,12 @@ impl ChildGuard {
8990
use std::os::unix::process::CommandExt;
9091
cmd.process_group(0);
9192
}
92-
let child = cmd.spawn()?;
93+
#[cfg(windows)]
94+
{
95+
use std::os::windows::process::CommandExt;
96+
cmd.creation_flags(0x00000200); // CREATE_NEW_PROCESS_GROUP
97+
}
98+
let child = cmd.spawn_interruptible()?;
9399
Ok(Self { child })
94100
}
95101

@@ -105,6 +111,13 @@ impl ChildGuard {
105111
// Give the process some time to shut down gracefully
106112
std::thread::sleep(std::time::Duration::from_secs(2));
107113
}
114+
#[cfg(windows)]
115+
{
116+
use send_ctrlc::Interruptible;
117+
_ = self.child.terminate(); // CTRL_BREAK_EVENT, required to target process group
118+
// Give the process some time to shut down gracefully
119+
std::thread::sleep(std::time::Duration::from_secs(2));
120+
}
108121
}
109122
}
110123

crates/icp/src/network/managed/run.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,13 +345,13 @@ fn safe_eprintln(msg: &str) {
345345
async fn wait_for_shutdown(guard: &mut ShutdownGuard) -> ShutdownReason {
346346
match guard {
347347
ShutdownGuard::Container(_) => {
348-
_ = ctrl_c().await;
348+
stop_signal().await;
349349
safe_eprintln("Received Ctrl-C, shutting down PocketIC...");
350350
ShutdownReason::CtrlC
351351
}
352352
ShutdownGuard::Process(child) => {
353353
select!(
354-
_ = ctrl_c() => {
354+
_ = stop_signal() => {
355355
safe_eprintln("Received Ctrl-C, shutting down PocketIC...");
356356
ShutdownReason::CtrlC
357357
}
@@ -364,6 +364,28 @@ async fn wait_for_shutdown(guard: &mut ShutdownGuard) -> ShutdownReason {
364364
}
365365
}
366366

367+
#[cfg(unix)]
368+
async fn stop_signal() {
369+
use tokio::signal::unix::{SignalKind, signal};
370+
let mut sigterm = signal(SignalKind::terminate()).unwrap();
371+
select! {
372+
_ = ctrl_c() => {},
373+
_ = sigterm.recv() => {},
374+
}
375+
}
376+
377+
#[cfg(windows)]
378+
async fn stop_signal() {
379+
use tokio::signal::windows::{ctrl_break, ctrl_close};
380+
let mut ctrl_break = ctrl_break().unwrap();
381+
let mut ctrl_close = ctrl_close().unwrap();
382+
select! {
383+
_ = ctrl_c() => {},
384+
_ = ctrl_break.recv() => {},
385+
_ = ctrl_close.recv() => {},
386+
}
387+
}
388+
367389
/// Yields immediately if the child exits.
368390
pub async fn notice_child_exit(child: &mut Child) -> ChildExitError {
369391
loop {

0 commit comments

Comments
 (0)