@@ -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" ,
@@ -748,7 +750,7 @@ impl Command {
748
750
msg. msg_controllen = mem:: size_of :: < Cmsg > ( ) as _ ;
749
751
msg. msg_control = & mut cmsg as * mut _ as * mut _ ;
750
752
751
- match cvt_r ( || libc:: recvmsg ( sock. as_raw ( ) , & mut msg, 0 ) ) {
753
+ match cvt_r ( || libc:: recvmsg ( sock. as_raw ( ) , & mut msg, libc :: MSG_CMSG_CLOEXEC ) ) {
752
754
Err ( _) => return -1 ,
753
755
Ok ( _) => { }
754
756
}
@@ -787,7 +789,7 @@ pub struct Process {
787
789
// On Linux, stores the pidfd created for this child.
788
790
// This is None if the user did not request pidfd creation,
789
791
// or if the pidfd could not be created for some reason
790
- // (e.g. the `clone3 ` syscall was not available).
792
+ // (e.g. the `pidfd_open ` syscall was not available).
791
793
#[ cfg( target_os = "linux" ) ]
792
794
pidfd : Option < PidFd > ,
793
795
}
@@ -816,17 +818,41 @@ impl Process {
816
818
// and used for another process, and we probably shouldn't be killing
817
819
// random processes, so return Ok because the process has exited already.
818
820
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) ;
822
836
}
837
+ cvt ( unsafe { libc:: kill ( self . pid , libc:: SIGKILL ) } ) . map ( drop)
823
838
}
824
839
825
840
pub fn wait ( & mut self ) -> io:: Result < ExitStatus > {
826
841
use crate :: sys:: cvt_r;
827
842
if let Some ( status) = self . status {
828
843
return Ok ( status) ;
829
844
}
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
+ }
830
856
let mut status = 0 as c_int ;
831
857
cvt_r ( || unsafe { libc:: waitpid ( self . pid , & mut status, 0 ) } ) ?;
832
858
self . status = Some ( ExitStatus :: new ( status) ) ;
@@ -837,6 +863,25 @@ impl Process {
837
863
if let Some ( status) = self . status {
838
864
return Ok ( Some ( status) ) ;
839
865
}
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
+ }
840
885
let mut status = 0 as c_int ;
841
886
let pid = cvt ( unsafe { libc:: waitpid ( self . pid , & mut status, libc:: WNOHANG ) } ) ?;
842
887
if pid == 0 {
@@ -866,6 +911,20 @@ impl ExitStatus {
866
911
ExitStatus ( status)
867
912
}
868
913
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
+
869
928
fn exited ( & self ) -> bool {
870
929
libc:: WIFEXITED ( self . 0 )
871
930
}
0 commit comments