@@ -9,6 +9,8 @@ use core::ffi::NonZero_c_int;
9
9
10
10
#[ cfg( target_os = "linux" ) ]
11
11
use crate :: os:: linux:: process:: PidFd ;
12
+ #[ cfg( target_os = "linux" ) ]
13
+ use crate :: os:: unix:: io:: AsRawFd ;
12
14
13
15
#[ cfg( any(
14
16
target_os = "macos" ,
@@ -696,11 +698,12 @@ impl Command {
696
698
697
699
msg. msg_iov = & mut iov as * mut _ as * mut _ ;
698
700
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 _ ;
701
701
702
702
// only attach cmsg if we successfully acquired the pidfd
703
703
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
+
704
707
let hdr = CMSG_FIRSTHDR ( & mut msg as * mut _ as * mut _ ) ;
705
708
( * hdr) . cmsg_level = SOL_SOCKET ;
706
709
( * hdr) . cmsg_type = SCM_RIGHTS ;
@@ -717,7 +720,7 @@ impl Command {
717
720
// so we get a consistent SEQPACKET order
718
721
match cvt_r ( || libc:: sendmsg ( sock. as_raw ( ) , & msg, 0 ) ) {
719
722
Ok ( 0 ) => { }
720
- _ => rtabort ! ( "failed to communicate with parent process" ) ,
723
+ other => rtabort ! ( "failed to communicate with parent process. {:?}" , other ) ,
721
724
}
722
725
}
723
726
}
@@ -748,7 +751,7 @@ impl Command {
748
751
msg. msg_controllen = mem:: size_of :: < Cmsg > ( ) as _ ;
749
752
msg. msg_control = & mut cmsg as * mut _ as * mut _ ;
750
753
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 ) ) {
752
755
Err ( _) => return -1 ,
753
756
Ok ( _) => { }
754
757
}
@@ -787,7 +790,7 @@ pub struct Process {
787
790
// On Linux, stores the pidfd created for this child.
788
791
// This is None if the user did not request pidfd creation,
789
792
// 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).
791
794
#[ cfg( target_os = "linux" ) ]
792
795
pidfd : Option < PidFd > ,
793
796
}
@@ -816,17 +819,41 @@ impl Process {
816
819
// and used for another process, and we probably shouldn't be killing
817
820
// random processes, so return Ok because the process has exited already.
818
821
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) ;
822
837
}
838
+ cvt ( unsafe { libc:: kill ( self . pid , libc:: SIGKILL ) } ) . map ( drop)
823
839
}
824
840
825
841
pub fn wait ( & mut self ) -> io:: Result < ExitStatus > {
826
842
use crate :: sys:: cvt_r;
827
843
if let Some ( status) = self . status {
828
844
return Ok ( status) ;
829
845
}
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
+ }
830
857
let mut status = 0 as c_int ;
831
858
cvt_r ( || unsafe { libc:: waitpid ( self . pid , & mut status, 0 ) } ) ?;
832
859
self . status = Some ( ExitStatus :: new ( status) ) ;
@@ -837,6 +864,25 @@ impl Process {
837
864
if let Some ( status) = self . status {
838
865
return Ok ( Some ( status) ) ;
839
866
}
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
+ }
840
886
let mut status = 0 as c_int ;
841
887
let pid = cvt ( unsafe { libc:: waitpid ( self . pid , & mut status, libc:: WNOHANG ) } ) ?;
842
888
if pid == 0 {
@@ -866,6 +912,20 @@ impl ExitStatus {
866
912
ExitStatus ( status)
867
913
}
868
914
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
+
869
929
fn exited ( & self ) -> bool {
870
930
libc:: WIFEXITED ( self . 0 )
871
931
}
0 commit comments