@@ -9,6 +9,8 @@ use core::ffi::NonZero_c_int;
99
1010#[ cfg( target_os = "linux" ) ]
1111use crate :: os:: linux:: process:: PidFd ;
12+ #[ cfg( target_os = "linux" ) ]
13+ use crate :: os:: unix:: io:: AsRawFd ;
1214
1315#[ cfg( any(
1416 target_os = "macos" ,
@@ -816,17 +818,41 @@ impl Process {
816818 // and used for another process, and we probably shouldn't be killing
817819 // random processes, so return Ok because the process has exited already.
818820 if self . status . is_some ( ) {
819- Ok ( ( ) )
820- } else {
821- cvt ( unsafe { libc:: kill ( self . pid , libc:: SIGKILL ) } ) . map ( drop)
821+ return Ok ( ( ) ) ;
822+ }
823+ #[ cfg( target_os = "linux" ) ]
824+ if let Some ( pid_fd) = self . pidfd . as_ref ( ) {
825+ // pidfd_send_signal predates pidfd_open. so if we were able to get an fd then sending signals will work too
826+ return cvt ( unsafe {
827+ libc:: syscall (
828+ libc:: SYS_pidfd_send_signal ,
829+ pid_fd. as_raw_fd ( ) ,
830+ libc:: SIGKILL ,
831+ crate :: ptr:: null :: < ( ) > ( ) ,
832+ 0 ,
833+ )
834+ } )
835+ . map ( drop) ;
822836 }
837+ cvt ( unsafe { libc:: kill ( self . pid , libc:: SIGKILL ) } ) . map ( drop)
823838 }
824839
825840 pub fn wait ( & mut self ) -> io:: Result < ExitStatus > {
826841 use crate :: sys:: cvt_r;
827842 if let Some ( status) = self . status {
828843 return Ok ( status) ;
829844 }
845+ #[ cfg( target_os = "linux" ) ]
846+ if let Some ( pid_fd) = self . pidfd . as_ref ( ) {
847+ let mut siginfo: libc:: siginfo_t = unsafe { crate :: mem:: zeroed ( ) } ;
848+
849+ cvt_r ( || unsafe {
850+ libc:: waitid ( libc:: P_PIDFD , pid_fd. as_raw_fd ( ) as u32 , & mut siginfo, libc:: WEXITED )
851+ } ) ?;
852+ let status = ExitStatus :: from_waitid_siginfo ( siginfo) ;
853+ self . status = Some ( status) ;
854+ return Ok ( status) ;
855+ }
830856 let mut status = 0 as c_int ;
831857 cvt_r ( || unsafe { libc:: waitpid ( self . pid , & mut status, 0 ) } ) ?;
832858 self . status = Some ( ExitStatus :: new ( status) ) ;
@@ -837,6 +863,25 @@ impl Process {
837863 if let Some ( status) = self . status {
838864 return Ok ( Some ( status) ) ;
839865 }
866+ #[ cfg( target_os = "linux" ) ]
867+ if let Some ( pid_fd) = self . pidfd . as_ref ( ) {
868+ let mut siginfo: libc:: siginfo_t = unsafe { crate :: mem:: zeroed ( ) } ;
869+
870+ cvt ( unsafe {
871+ libc:: waitid (
872+ libc:: P_PIDFD ,
873+ pid_fd. as_raw_fd ( ) as u32 ,
874+ & mut siginfo,
875+ libc:: WEXITED | libc:: WNOHANG ,
876+ )
877+ } ) ?;
878+ if unsafe { siginfo. si_pid ( ) } == 0 {
879+ return Ok ( None ) ;
880+ }
881+ let status = ExitStatus :: from_waitid_siginfo ( siginfo) ;
882+ self . status = Some ( status) ;
883+ return Ok ( Some ( status) ) ;
884+ }
840885 let mut status = 0 as c_int ;
841886 let pid = cvt ( unsafe { libc:: waitpid ( self . pid , & mut status, libc:: WNOHANG ) } ) ?;
842887 if pid == 0 {
@@ -866,6 +911,20 @@ impl ExitStatus {
866911 ExitStatus ( status)
867912 }
868913
914+ #[ cfg( target_os = "linux" ) ]
915+ pub fn from_waitid_siginfo ( siginfo : libc:: siginfo_t ) -> ExitStatus {
916+ let status = unsafe { siginfo. si_status ( ) } ;
917+
918+ match siginfo. si_code {
919+ libc:: CLD_EXITED => ExitStatus ( ( status & 0xff ) << 8 ) ,
920+ libc:: CLD_KILLED => ExitStatus ( status) ,
921+ libc:: CLD_DUMPED => ExitStatus ( status | 0x80 ) ,
922+ libc:: CLD_CONTINUED => ExitStatus ( 0xffff ) ,
923+ libc:: CLD_STOPPED | libc:: CLD_TRAPPED => ExitStatus ( ( ( status & 0xff ) << 8 ) | 0x7f ) ,
924+ _ => unreachable ! ( "waitid() should only return the above codes" ) ,
925+ }
926+ }
927+
869928 fn exited ( & self ) -> bool {
870929 libc:: WIFEXITED ( self . 0 )
871930 }
0 commit comments