@@ -2385,75 +2385,99 @@ fn wait_for_child_exit(child: &mut Child, timeout: Duration) -> bool {
23852385 }
23862386}
23872387
2388+ fn run_stop_command ( pid : u32 , label : & str , program : & str , args : & [ & str ] ) -> io:: Result < ExitStatus > {
2389+ let status = Command :: new ( program)
2390+ . args ( args)
2391+ . stdout ( Stdio :: null ( ) )
2392+ . stderr ( Stdio :: null ( ) )
2393+ . stdin ( Stdio :: null ( ) )
2394+ . status ( ) ;
2395+
2396+ match & status {
2397+ Ok ( exit_status) if exit_status. success ( ) => { }
2398+ Ok ( exit_status) => append_desktop_log ( & format ! (
2399+ "{label} returned non-zero: pid={pid}, status={exit_status:?}"
2400+ ) ) ,
2401+ Err ( error) => append_desktop_log ( & format ! (
2402+ "{label} failed to start: pid={pid}, error={error}"
2403+ ) ) ,
2404+ }
2405+
2406+ status
2407+ }
2408+
2409+ fn compute_followup_wait ( timeout : Duration , max_extra_wait : Duration ) -> Duration {
2410+ if timeout. is_zero ( ) {
2411+ Duration :: ZERO
2412+ } else {
2413+ ( timeout / 4 )
2414+ . max ( Duration :: from_millis ( FORCE_STOP_WAIT_MIN_MS ) )
2415+ . min ( max_extra_wait)
2416+ }
2417+ }
2418+
23882419/// Attempt to stop a child process gracefully within `timeout`.
23892420///
23902421/// On the force-kill path, a follow-up wait is derived from `timeout` (`timeout / 4`)
23912422/// and capped per-platform:
23922423/// - Windows: up to 2200ms.
23932424/// - Non-Windows: up to 1500ms.
2425+ #[ cfg( target_os = "windows" ) ]
23942426fn stop_child_process_gracefully ( child : & mut Child , timeout : Duration ) -> bool {
23952427 let pid = child. id ( ) ;
23962428 let pid_arg = pid. to_string ( ) ;
23972429
2398- let run_stop_command = |label : & str , program : & str , args : & [ & str ] | -> io:: Result < ExitStatus > {
2399- let status = Command :: new ( program)
2400- . args ( args)
2401- . stdout ( Stdio :: null ( ) )
2402- . stderr ( Stdio :: null ( ) )
2403- . stdin ( Stdio :: null ( ) )
2404- . status ( ) ;
2405-
2406- match & status {
2407- Ok ( exit_status) if exit_status. success ( ) => { }
2408- Ok ( exit_status) => append_desktop_log ( & format ! (
2409- "{label} returned non-zero: pid={pid}, status={exit_status:?}"
2410- ) ) ,
2411- Err ( error) => append_desktop_log ( & format ! (
2412- "{label} failed to start: pid={pid}, error={error}"
2413- ) ) ,
2414- }
2415-
2416- status
2417- } ;
2418-
2419- #[ cfg( target_os = "windows" ) ]
24202430 let graceful_status = run_stop_command (
2431+ pid,
24212432 "taskkill graceful stop" ,
24222433 "taskkill" ,
24232434 & [ "/pid" , & pid_arg, "/t" ] ,
24242435 ) ;
2425- #[ cfg( not( target_os = "windows" ) ) ]
2426- let graceful_status = run_stop_command ( "kill -TERM" , "kill" , & [ "-TERM" , & pid_arg] ) ;
24272436
24282437 if wait_for_child_exit ( child, timeout) {
24292438 return true ;
24302439 }
24312440
2432- #[ cfg( target_os = "windows" ) ]
24332441 let force_status = run_stop_command (
2442+ pid,
24342443 "taskkill force stop" ,
24352444 "taskkill" ,
24362445 & [ "/pid" , & pid_arg, "/t" , "/f" ] ,
24372446 ) ;
2438- #[ cfg( not( target_os = "windows" ) ) ]
2439- let force_status = run_stop_command ( "kill -KILL" , "kill" , & [ "-KILL" , & pid_arg] ) ;
24402447
2441- #[ cfg( target_os = "windows" ) ]
2442- let max_extra_wait = Duration :: from_millis ( FORCE_STOP_WAIT_MAX_WINDOWS_MS ) ;
2443- #[ cfg( not( target_os = "windows" ) ) ]
2444- let max_extra_wait = Duration :: from_millis ( FORCE_STOP_WAIT_MAX_NON_WINDOWS_MS ) ;
2448+ let followup_wait = compute_followup_wait (
2449+ timeout,
2450+ Duration :: from_millis ( FORCE_STOP_WAIT_MAX_WINDOWS_MS ) ,
2451+ ) ;
2452+ append_desktop_log ( & format ! (
2453+ "child graceful stop timed out, force-kill issued: pid={pid}, graceful={graceful_status:?}, force={force_status:?}, followup_wait_ms={}" ,
2454+ followup_wait. as_millis( ) ,
2455+ ) ) ;
2456+ wait_for_child_exit ( child, followup_wait)
2457+ }
24452458
2446- let followup_wait = if timeout. is_zero ( ) {
2447- Duration :: ZERO
2448- } else {
2449- ( timeout / 4 )
2450- . max ( Duration :: from_millis ( FORCE_STOP_WAIT_MIN_MS ) )
2451- . min ( max_extra_wait)
2452- } ;
2459+ #[ cfg( not( target_os = "windows" ) ) ]
2460+ fn stop_child_process_gracefully ( child : & mut Child , timeout : Duration ) -> bool {
2461+ let pid = child. id ( ) ;
2462+ let pid_arg = pid. to_string ( ) ;
2463+
2464+ let graceful_status = run_stop_command ( pid, "kill -TERM" , "kill" , & [ "-TERM" , & pid_arg] ) ;
2465+
2466+ if wait_for_child_exit ( child, timeout) {
2467+ return true ;
2468+ }
2469+
2470+ let force_status = run_stop_command ( pid, "kill -KILL" , "kill" , & [ "-KILL" , & pid_arg] ) ;
2471+
2472+ let followup_wait = compute_followup_wait (
2473+ timeout,
2474+ Duration :: from_millis ( FORCE_STOP_WAIT_MAX_NON_WINDOWS_MS ) ,
2475+ ) ;
24532476 append_desktop_log ( & format ! (
24542477 "child graceful stop timed out, force-kill issued: pid={pid}, graceful={graceful_status:?}, force={force_status:?}, followup_wait_ms={}" ,
24552478 followup_wait. as_millis( ) ,
24562479 ) ) ;
2480+
24572481 wait_for_child_exit ( child, followup_wait)
24582482}
24592483
0 commit comments