File tree Expand file tree Collapse file tree 2 files changed +38
-0
lines changed
Expand file tree Collapse file tree 2 files changed +38
-0
lines changed Original file line number Diff line number Diff line change @@ -24,6 +24,19 @@ pub trait CapStdExtCommandExt {
2424
2525 /// Use the given directory as the current working directory for the process.
2626 fn cwd_dir ( & mut self , dir : Dir ) -> & mut Self ;
27+
28+ /// On Linux, arrange for [`SIGTERM`] to be delivered to the child if the
29+ /// parent *thread* exits. This helps avoid leaking child processes if
30+ /// the parent crashes for example.
31+ ///
32+ /// # IMPORTANT
33+ ///
34+ /// Due to the semantics of <https://man7.org/linux/man-pages/man2/prctl.2.html> this
35+ /// will cause the child to exit when the parent *thread* (not process) exits. In
36+ /// particular this can become problematic when used with e.g. a threadpool such
37+ /// as Tokio's <https://kobzol.github.io/rust/2025/02/23/tokio-plus-prctl-equals-nasty-bug.html>.
38+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
39+ fn lifecycle_bind_to_parent_thread ( & mut self ) -> & mut Self ;
2740}
2841
2942#[ allow( unsafe_code) ]
@@ -58,6 +71,20 @@ impl CapStdExtCommandExt for std::process::Command {
5871 }
5972 self
6073 }
74+
75+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
76+ fn lifecycle_bind_to_parent_thread ( & mut self ) -> & mut Self {
77+ // SAFETY: This API is safe to call in a forked child.
78+ unsafe {
79+ self . pre_exec ( || {
80+ rustix:: process:: set_parent_process_death_signal ( Some (
81+ rustix:: process:: Signal :: TERM ,
82+ ) )
83+ . map_err ( Into :: into)
84+ } ) ;
85+ }
86+ self
87+ }
6188}
6289
6390#[ cfg( test) ]
Original file line number Diff line number Diff line change @@ -791,3 +791,14 @@ fn test_big_xattr() -> Result<()> {
791791
792792 Ok ( ( ) )
793793}
794+
795+ #[ test]
796+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
797+ fn test_lifecycle_bind_to_parent_thread ( ) -> Result < ( ) > {
798+ let status = Command :: new ( "true" )
799+ . lifecycle_bind_to_parent_thread ( )
800+ . status ( ) ?;
801+ assert ! ( status. success( ) ) ;
802+
803+ Ok ( ( ) )
804+ }
You can’t perform that action at this time.
0 commit comments