@@ -159,6 +159,62 @@ pub fn kill_process(pid: u32) -> bool {
159159 }
160160}
161161
162+ /// Kill a daemon process and all its children (process group).
163+ /// Sends SIGTERM first, waits for the process to exit, then sends SIGKILL if needed.
164+ /// Returns true if the process was successfully killed.
165+ pub fn kill_daemon_gracefully ( pid : u32 ) -> bool {
166+ #[ cfg( unix) ]
167+ {
168+ // First, send SIGTERM to the daemon process itself
169+ // The daemon's signal handler should propagate to children
170+ let term_result = unsafe { libc:: kill ( pid as i32 , libc:: SIGTERM ) } ;
171+ if term_result != 0 {
172+ // Process doesn't exist or we don't have permission
173+ return false ;
174+ }
175+
176+ // Wait up to 6 seconds for the daemon to shut down gracefully
177+ // (daemon waits 5s internally for children to exit, plus 1s buffer)
178+ for _ in 0 ..60 {
179+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 100 ) ) ;
180+ if !is_process_alive ( pid) {
181+ return true ;
182+ }
183+ }
184+
185+ // If still alive after 6 seconds, send SIGKILL to the process group
186+ // Use negative PID to target the entire process group
187+ let pgid = unsafe { libc:: getpgid ( pid as i32 ) } ;
188+ if pgid > 0 {
189+ let _ = unsafe { libc:: killpg ( pgid, libc:: SIGKILL ) } ;
190+ }
191+ // Also send SIGKILL directly to the daemon in case it's not the process group leader
192+ let _ = unsafe { libc:: kill ( pid as i32 , libc:: SIGKILL ) } ;
193+
194+ // Wait a bit for the process to actually die
195+ for _ in 0 ..10 {
196+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 100 ) ) ;
197+ if !is_process_alive ( pid) {
198+ return true ;
199+ }
200+ }
201+
202+ // Return true even if we couldn't verify death - we did our best
203+ true
204+ }
205+
206+ #[ cfg( windows) ]
207+ {
208+ // On Windows, just use TerminateProcess (no graceful shutdown)
209+ kill_process ( pid)
210+ }
211+
212+ #[ cfg( not( any( unix, windows) ) ) ]
213+ {
214+ false
215+ }
216+ }
217+
162218pub fn cleanup_stale_daemons ( ) -> Result < ( ) , Error > {
163219 let daemons
164220 = list_daemons ( ) ?;
0 commit comments