@@ -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" ,
@@ -696,11 +698,12 @@ impl Command {
696698
697699 msg. msg_iov = & mut iov as * mut _ as * mut _ ;
698700 msg. msg_iovlen = 1 ;
699- msg. msg_controllen = mem:: size_of_val ( & cmsg. buf ) as _ ;
700- msg. msg_control = & mut cmsg. buf as * mut _ as * mut _ ;
701701
702702 // only attach cmsg if we successfully acquired the pidfd
703703 if pidfd >= 0 {
704+ msg. msg_controllen = mem:: size_of_val ( & cmsg. buf ) as _ ;
705+ msg. msg_control = & mut cmsg. buf as * mut _ as * mut _ ;
706+
704707 let hdr = CMSG_FIRSTHDR ( & mut msg as * mut _ as * mut _ ) ;
705708 ( * hdr) . cmsg_level = SOL_SOCKET ;
706709 ( * hdr) . cmsg_type = SCM_RIGHTS ;
@@ -717,7 +720,7 @@ impl Command {
717720 // so we get a consistent SEQPACKET order
718721 match cvt_r ( || libc:: sendmsg ( sock. as_raw ( ) , & msg, 0 ) ) {
719722 Ok ( 0 ) => { }
720- _ => rtabort ! ( "failed to communicate with parent process" ) ,
723+ other => rtabort ! ( "failed to communicate with parent process. {:?}" , other ) ,
721724 }
722725 }
723726 }
@@ -748,7 +751,7 @@ impl Command {
748751 msg. msg_controllen = mem:: size_of :: < Cmsg > ( ) as _ ;
749752 msg. msg_control = & mut cmsg as * mut _ as * mut _ ;
750753
751- match cvt_r ( || libc:: recvmsg ( sock. as_raw ( ) , & mut msg, 0 ) ) {
754+ match cvt_r ( || libc:: recvmsg ( sock. as_raw ( ) , & mut msg, libc :: MSG_CMSG_CLOEXEC ) ) {
752755 Err ( _) => return -1 ,
753756 Ok ( _) => { }
754757 }
@@ -787,7 +790,7 @@ pub struct Process {
787790 // On Linux, stores the pidfd created for this child.
788791 // This is None if the user did not request pidfd creation,
789792 // or if the pidfd could not be created for some reason
790- // (e.g. the `clone3 ` syscall was not available).
793+ // (e.g. the `pidfd_open ` syscall was not available).
791794 #[ cfg( target_os = "linux" ) ]
792795 pidfd : Option < PidFd > ,
793796}
@@ -816,17 +819,41 @@ impl Process {
816819 // and used for another process, and we probably shouldn't be killing
817820 // random processes, so return Ok because the process has exited already.
818821 if self . status . is_some ( ) {
819- Ok ( ( ) )
820- } else {
821- cvt ( unsafe { libc:: kill ( self . pid , libc:: SIGKILL ) } ) . map ( drop)
822+ return Ok ( ( ) ) ;
823+ }
824+ #[ cfg( target_os = "linux" ) ]
825+ if let Some ( pid_fd) = self . pidfd . as_ref ( ) {
826+ // pidfd_send_signal predates pidfd_open. so if we were able to get an fd then sending signals will work too
827+ return cvt ( unsafe {
828+ libc:: syscall (
829+ libc:: SYS_pidfd_send_signal ,
830+ pid_fd. as_raw_fd ( ) ,
831+ libc:: SIGKILL ,
832+ crate :: ptr:: null :: < ( ) > ( ) ,
833+ 0 ,
834+ )
835+ } )
836+ . map ( drop) ;
822837 }
838+ cvt ( unsafe { libc:: kill ( self . pid , libc:: SIGKILL ) } ) . map ( drop)
823839 }
824840
825841 pub fn wait ( & mut self ) -> io:: Result < ExitStatus > {
826842 use crate :: sys:: cvt_r;
827843 if let Some ( status) = self . status {
828844 return Ok ( status) ;
829845 }
846+ #[ cfg( target_os = "linux" ) ]
847+ if let Some ( pid_fd) = self . pidfd . as_ref ( ) {
848+ let mut siginfo: libc:: siginfo_t = unsafe { crate :: mem:: zeroed ( ) } ;
849+
850+ cvt_r ( || unsafe {
851+ libc:: waitid ( libc:: P_PIDFD , pid_fd. as_raw_fd ( ) as u32 , & mut siginfo, libc:: WEXITED )
852+ } ) ?;
853+ let status = ExitStatus :: from_waitid_siginfo ( siginfo) ;
854+ self . status = Some ( status) ;
855+ return Ok ( status) ;
856+ }
830857 let mut status = 0 as c_int ;
831858 cvt_r ( || unsafe { libc:: waitpid ( self . pid , & mut status, 0 ) } ) ?;
832859 self . status = Some ( ExitStatus :: new ( status) ) ;
@@ -837,6 +864,25 @@ impl Process {
837864 if let Some ( status) = self . status {
838865 return Ok ( Some ( status) ) ;
839866 }
867+ #[ cfg( target_os = "linux" ) ]
868+ if let Some ( pid_fd) = self . pidfd . as_ref ( ) {
869+ let mut siginfo: libc:: siginfo_t = unsafe { crate :: mem:: zeroed ( ) } ;
870+
871+ cvt ( unsafe {
872+ libc:: waitid (
873+ libc:: P_PIDFD ,
874+ pid_fd. as_raw_fd ( ) as u32 ,
875+ & mut siginfo,
876+ libc:: WEXITED | libc:: WNOHANG ,
877+ )
878+ } ) ?;
879+ if unsafe { siginfo. si_pid ( ) } == 0 {
880+ return Ok ( None ) ;
881+ }
882+ let status = ExitStatus :: from_waitid_siginfo ( siginfo) ;
883+ self . status = Some ( status) ;
884+ return Ok ( Some ( status) ) ;
885+ }
840886 let mut status = 0 as c_int ;
841887 let pid = cvt ( unsafe { libc:: waitpid ( self . pid , & mut status, libc:: WNOHANG ) } ) ?;
842888 if pid == 0 {
@@ -866,6 +912,20 @@ impl ExitStatus {
866912 ExitStatus ( status)
867913 }
868914
915+ #[ cfg( target_os = "linux" ) ]
916+ pub fn from_waitid_siginfo ( siginfo : libc:: siginfo_t ) -> ExitStatus {
917+ let status = unsafe { siginfo. si_status ( ) } ;
918+
919+ match siginfo. si_code {
920+ libc:: CLD_EXITED => ExitStatus ( ( status & 0xff ) << 8 ) ,
921+ libc:: CLD_KILLED => ExitStatus ( status) ,
922+ libc:: CLD_DUMPED => ExitStatus ( status | 0x80 ) ,
923+ libc:: CLD_CONTINUED => ExitStatus ( 0xffff ) ,
924+ libc:: CLD_STOPPED | libc:: CLD_TRAPPED => ExitStatus ( ( ( status & 0xff ) << 8 ) | 0x7f ) ,
925+ _ => unreachable ! ( "waitid() should only return the above codes" ) ,
926+ }
927+ }
928+
869929 fn exited ( & self ) -> bool {
870930 libc:: WIFEXITED ( self . 0 )
871931 }
0 commit comments