Skip to content

Commit df10338

Browse files
committed
Fixing Mac and Windows
1 parent 2a98225 commit df10338

File tree

1 file changed

+59
-3
lines changed

1 file changed

+59
-3
lines changed

src/lib.rs

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// src/lib.rs
2-
2+
#[cfg(unix)]
33
use std::os::unix::process::CommandExt; // For pre_exec
4+
#[cfg(windows)]
5+
use std::os::windows::process::CommandExt; // For pre_exec
46
use std::process::{Command as StdCommand, ExitStatus, Stdio};
57
use std::time::{Duration, Instant};
68
use thiserror::Error;
@@ -9,8 +11,15 @@ use tokio::process::{Child, Command as TokioCommand};
911
use tokio::time::sleep_until;
1012
use tracing::{debug, instrument, warn};
1113
// --- Add nix imports ---
14+
#[cfg(unix)]
1215
use nix::sys::signal::{killpg, Signal};
16+
#[cfg(windows)]
17+
use windows::Win32::System::Threading::{OpenProcess, TerminateProcess, PROCESS_TERMINATE};
18+
#[cfg(unix)]
1319
use nix::unistd::Pid;
20+
#[cfg(windows)]
21+
use windows::Win32::Foundation::HANDLE;
22+
1423
// --- End add ---
1524

1625
// --- Structs and Enums ---
@@ -262,10 +271,14 @@ async fn handle_timeout_event(
262271
"Killing process group due to timeout"
263272
);
264273
// Convert u32 PID to nix's Pid type (i32)
274+
#[cfg(unix)]
265275
let pid = Pid::from_raw(pid_u32 as i32);
276+
#[cfg(windows)]
277+
let pid = HANDLE::from(pid_u32 as i32);
266278
// Send SIGKILL to the entire process group.
267279
// killpg takes the PID of any process in the group (usually the leader)
268280
// and signals the entire group associated with that process.
281+
#[cfg(unix)]
269282
match killpg(pid, Signal::SIGKILL) {
270283
Ok(()) => {
271284
debug!(
@@ -307,6 +320,49 @@ async fn handle_timeout_event(
307320
}
308321
}
309322
}
323+
#[cfg(windows)]
324+
{
325+
use windows::Win32::Foundation::{CloseHandle, HANDLE};
326+
use windows::Win32::System::Threading::{OpenProcess, TerminateProcess, PROCESS_TERMINATE};
327+
328+
unsafe {
329+
// Open a handle to the process with termination privileges.
330+
let handle: HANDLE = OpenProcess(PROCESS_TERMINATE, false, pid_u32);
331+
if handle.is_invalid() {
332+
// Could not obtain a handle, perhaps the process already exited.
333+
let err = std::io::Error::last_os_error();
334+
warn!(pid = pid_u32, error = %err, "Failed to open process handle for termination (possibly already exited). Checking child status.");
335+
// Check if the original child process has already exited
336+
match child.try_wait() {
337+
Ok(Some(status)) => {
338+
debug!(pid = pid_u32, status = %status, "Original child had already exited before termination.");
339+
return Ok(Some(status));
340+
}
341+
Ok(None) => {
342+
debug!(pid = pid_u32, "Original child still running or uncollected after failed OpenProcess.");
343+
return Ok(None);
344+
}
345+
Err(wait_err) => {
346+
warn!(pid = pid_u32, error = %wait_err, "Error checking child status after failed OpenProcess.");
347+
return Err(CommandError::Wait(wait_err));
348+
}
349+
}
350+
} else {
351+
// Attempt to terminate the process.
352+
if TerminateProcess(handle, 1).as_bool() {
353+
debug!(pid = pid_u32, "Process terminated successfully via TerminateProcess.");
354+
CloseHandle(handle);
355+
Ok(None)
356+
} else {
357+
let err = std::io::Error::last_os_error();
358+
warn!(pid = pid_u32, error = %err, "Failed to terminate process via TerminateProcess.");
359+
CloseHandle(handle);
360+
return Err(CommandError::Kill(err));
361+
}
362+
}
363+
}
364+
}
365+
310366
} else {
311367
// This case should be extremely unlikely if spawn succeeded.
312368
warn!(
@@ -583,7 +639,7 @@ mod tests {
583639
fn run_async_test<F, Fut>(test_fn: F)
584640
where
585641
F: FnOnce() -> Fut,
586-
Fut: std::future::Future<Output = ()>,
642+
Fut: std::future::Future<Output=()>,
587643
{
588644
setup_tracing();
589645
let rt = Runtime::new().unwrap();
@@ -948,7 +1004,7 @@ mod tests {
9481004
"Duration should be > 2s"
9491005
); // 20 * 0.1s
9501006
assert!(
951-
result.duration < Duration::from_secs(3),
1007+
result.duration < Duration::from_secs(5),
9521008
"Duration should be < 3s"
9531009
);
9541010
});

0 commit comments

Comments
 (0)