@@ -476,35 +476,47 @@ impl Command {
476476
477477                weak! {  fn  pidfd_getpid( libc:: c_int)  -> libc:: c_int } 
478478
479-                 static  PIDFD_SPAWN_SUPPORTED :  AtomicU8  = AtomicU8 :: new( 0 ) ; 
479+                 static  PIDFD_SUPPORTED :  AtomicU8  = AtomicU8 :: new( 0 ) ; 
480480                const  UNKNOWN :  u8  = 0 ; 
481-                 const  YES :  u8  = 1 ; 
482-                 // NO currently forces a fallback to fork/exec. We could be more nuanced here and keep using spawn 
483-                 // if we know pidfd's aren't supported at all and the fallback would be futile. 
484-                 const  NO :  u8  = 2 ; 
481+                 const  SPAWN :  u8  = 1 ; 
482+                 // Obtaining a pidfd via the fork+exec path might work 
483+                 const  FORK_EXEC :  u8  = 2 ; 
484+                 // Neither pidfd_spawn nor fork/exec will get us a pidfd. 
485+                 // Instead we'll just posix_spawn if the other preconditions are met. 
486+                 const  NO :  u8  = 3 ; 
485487
486488                if  self . get_create_pidfd( )  { 
487-                     let  flag =  PIDFD_SPAWN_SUPPORTED . load( Ordering :: Relaxed ) ; 
488-                     if  flag  == NO  || pidfd_spawnp . get ( ) . is_none ( )  || pidfd_getpid . get ( ) . is_none ( )  { 
489+                     let  mut  support =  PIDFD_SUPPORTED . load( Ordering :: Relaxed ) ; 
490+                     if  support  == FORK_EXEC  { 
489491                        return  Ok ( None ) ; 
490492                    } 
491-                     if  flag  == UNKNOWN  { 
492-                         let   mut   support = NO ; 
493+                     if  support  == UNKNOWN  { 
494+                         support = NO ; 
493495                        let  our_pid = crate :: process:: id( ) ; 
494-                         let  pidfd =
495-                             unsafe  {  libc:: syscall( libc:: SYS_pidfd_open ,  our_pid,  0 )  }  as  libc:: c_int; 
496-                         if  pidfd >= 0  { 
497-                             let  pid = unsafe  {  pidfd_getpid. get( ) . unwrap( ) ( pidfd)  }  as  u32 ; 
498-                             unsafe  {  libc:: close( pidfd)  } ; 
499-                             if  pid == our_pid { 
500-                                 support = YES 
501-                             } ; 
496+                         let  pidfd = cvt( unsafe  {  libc:: syscall( libc:: SYS_pidfd_open ,  our_pid,  0 )  }  as  c_int) ; 
497+                         match  pidfd { 
498+                             Ok ( pidfd)  => { 
499+                                 support = FORK_EXEC ; 
500+                                 if  let  Some ( Ok ( pid) )  = pidfd_getpid. get( ) . map( |f| cvt( unsafe  {  f( pidfd)  }  as  i32 ) )  { 
501+                                     if  pidfd_spawnp. get( ) . is_some( )  && pid as  u32  == our_pid { 
502+                                         support = SPAWN 
503+                                     } 
504+                                 } 
505+                                 unsafe  {  libc:: close( pidfd)  } ; 
506+                             } 
507+                             Err ( e)  if  e. raw_os_error( )  == Some ( libc:: EMFILE )  => { 
508+                                 // We're temporarily(?) out of file descriptors.  In this case obtaining a pidfd would also fail 
509+                                 // Don't update the support flag so we can probe again later. 
510+                                 return  Err ( e) 
511+                             } 
512+                             _ => { } 
502513                        } 
503-                         PIDFD_SPAWN_SUPPORTED . store( support,  Ordering :: Relaxed ) ; 
504-                         if  support !=  YES  { 
514+                         PIDFD_SUPPORTED . store( support,  Ordering :: Relaxed ) ; 
515+                         if  support ==  FORK_EXEC  { 
505516                            return  Ok ( None ) ; 
506517                        } 
507518                    } 
519+                     core:: assert_matches:: debug_assert_matches!( support,  SPAWN  | NO ) ; 
508520                } 
509521            }  else { 
510522                if  self . get_create_pidfd( )  { 
@@ -691,7 +703,7 @@ impl Command {
691703            let  spawn_fn = retrying_libc_posix_spawnp; 
692704
693705            #[ cfg( target_os = "linux" ) ]  
694-             if  self . get_create_pidfd ( )  { 
706+             if  self . get_create_pidfd ( )  &&  PIDFD_SUPPORTED . load ( Ordering :: Relaxed )  ==  SPAWN   { 
695707                let  mut  pidfd:  libc:: c_int  = -1 ; 
696708                let  spawn_res = pidfd_spawnp. get ( ) . unwrap ( ) ( 
697709                    & mut  pidfd, 
@@ -706,7 +718,7 @@ impl Command {
706718                if  let  Err ( ref  e)  = spawn_res
707719                    && e. raw_os_error ( )  == Some ( libc:: ENOSYS ) 
708720                { 
709-                     PIDFD_SPAWN_SUPPORTED . store ( NO ,  Ordering :: Relaxed ) ; 
721+                     PIDFD_SUPPORTED . store ( FORK_EXEC ,  Ordering :: Relaxed ) ; 
710722                    return  Ok ( None ) ; 
711723                } 
712724                spawn_res?; 
0 commit comments