@@ -10,7 +10,7 @@ use crate::ExitStatus;
1010use std:: { io:: IsTerminal , sync:: atomic:: Ordering } ;
1111
1212#[ cfg( unix) ]
13- pub use foreground_pgroup :: stdin_fd;
13+ pub use child_pgroup :: stdin_fd;
1414
1515#[ cfg( unix) ]
1616use nix:: { sys:: signal, sys:: wait, unistd:: Pid } ;
@@ -35,6 +35,10 @@ pub struct ForegroundChild {
3535 inner : Child ,
3636 #[ cfg( unix) ]
3737 pipeline_state : Option < Arc < ( AtomicU32 , AtomicU32 ) > > ,
38+
39+ // this is unix-only since we don't have to deal with process groups in windows
40+ #[ cfg( unix) ]
41+ interactive : bool ,
3842}
3943
4044impl ForegroundChild {
@@ -47,32 +51,42 @@ impl ForegroundChild {
4751 pub fn spawn (
4852 mut command : Command ,
4953 interactive : bool ,
54+ background : bool ,
5055 pipeline_state : & Arc < ( AtomicU32 , AtomicU32 ) > ,
5156 ) -> io:: Result < Self > {
52- if interactive && io:: stdin ( ) . is_terminal ( ) {
57+ let interactive = interactive && io:: stdin ( ) . is_terminal ( ) ;
58+
59+ let uses_dedicated_process_group = interactive || background;
60+
61+ if uses_dedicated_process_group {
5362 let ( pgrp, pcnt) = pipeline_state. as_ref ( ) ;
5463 let existing_pgrp = pgrp. load ( Ordering :: SeqCst ) ;
55- foreground_pgroup :: prepare_command ( & mut command, existing_pgrp) ;
64+ child_pgroup :: prepare_command ( & mut command, existing_pgrp, background ) ;
5665 command
5766 . spawn ( )
5867 . map ( |child| {
59- foreground_pgroup:: set ( & child, existing_pgrp) ;
68+ child_pgroup:: set ( & child, existing_pgrp, background) ;
69+
6070 let _ = pcnt. fetch_add ( 1 , Ordering :: SeqCst ) ;
6171 if existing_pgrp == 0 {
6272 pgrp. store ( child. id ( ) , Ordering :: SeqCst ) ;
6373 }
6474 Self {
6575 inner : child,
6676 pipeline_state : Some ( pipeline_state. clone ( ) ) ,
77+ interactive,
6778 }
6879 } )
6980 . inspect_err ( |_e| {
70- foreground_pgroup:: reset ( ) ;
81+ if interactive {
82+ child_pgroup:: reset ( ) ;
83+ }
7184 } )
7285 } else {
7386 command. spawn ( ) . map ( |child| Self {
7487 inner : child,
7588 pipeline_state : None ,
89+ interactive,
7690 } )
7791 }
7892 }
@@ -103,10 +117,9 @@ impl ForegroundChild {
103117 } ) ) ;
104118 }
105119 Ok ( wait:: WaitStatus :: Stopped ( _, _) ) => {
106- // TODO: consider only bringing our
107- // process group back to foreground, if we are in an
108- // interactive session
109- foreground_pgroup:: reset ( ) ;
120+ if self . interactive {
121+ child_pgroup:: reset ( ) ;
122+ }
110123
111124 let handle = UnfreezeHandle { child_pid } ;
112125
@@ -212,7 +225,10 @@ impl Drop for ForegroundChild {
212225 if let Some ( ( pgrp, pcnt) ) = self . pipeline_state . as_deref ( ) {
213226 if pcnt. fetch_sub ( 1 , Ordering :: SeqCst ) == 1 {
214227 pgrp. store ( 0 , Ordering :: SeqCst ) ;
215- foreground_pgroup:: reset ( )
228+
229+ if self . interactive {
230+ child_pgroup:: reset ( )
231+ }
216232 }
217233 }
218234 }
@@ -339,7 +355,7 @@ impl ForegroundGuard {
339355 if pcnt. fetch_sub ( 1 , Ordering :: SeqCst ) == 1 {
340356 // Clean up if we are the last one around
341357 pgrp. store ( 0 , Ordering :: SeqCst ) ;
342- foreground_pgroup :: reset ( )
358+ child_pgroup :: reset ( )
343359 }
344360 }
345361 }
@@ -353,7 +369,7 @@ impl Drop for ForegroundGuard {
353369
354370// It's a simpler version of fish shell's external process handling.
355371#[ cfg( unix) ]
356- mod foreground_pgroup {
372+ mod child_pgroup {
357373 use nix:: {
358374 sys:: signal:: { sigaction, SaFlags , SigAction , SigHandler , SigSet , Signal } ,
359375 unistd:: { self , Pid } ,
@@ -377,7 +393,7 @@ mod foreground_pgroup {
377393 unsafe { BorrowedFd :: borrow_raw ( nix:: libc:: STDIN_FILENO ) }
378394 }
379395
380- pub fn prepare_command ( external_command : & mut Command , existing_pgrp : u32 ) {
396+ pub fn prepare_command ( external_command : & mut Command , existing_pgrp : u32 , background : bool ) {
381397 unsafe {
382398 // Safety:
383399 // POSIX only allows async-signal-safe functions to be called.
@@ -391,19 +407,13 @@ mod foreground_pgroup {
391407 // According to glibc's job control manual:
392408 // https://www.gnu.org/software/libc/manual/html_node/Launching-Jobs.html
393409 // This has to be done *both* in the parent and here in the child due to race conditions.
394- set_foreground_pid ( Pid :: this ( ) , existing_pgrp) ;
410+ set_foreground_pid ( Pid :: this ( ) , existing_pgrp, background ) ;
395411
396- // Reset signal handlers for child, sync with `terminal.rs`
412+ // `terminal.rs` makes the shell process ignore some signals,
413+ // so we set them to their default behavior for our child
397414 let default = SigAction :: new ( SigHandler :: SigDfl , SaFlags :: empty ( ) , SigSet :: empty ( ) ) ;
398- // SIGINT has special handling
415+
399416 let _ = sigaction ( Signal :: SIGQUIT , & default) ;
400- // We don't support background jobs, so keep some signals blocked for now
401- // let _ = sigaction(Signal::SIGTTIN, &default);
402- // let _ = sigaction(Signal::SIGTTOU, &default);
403- // We do need to reset SIGTSTP though, since some TUI
404- // applications implement their own Ctrl-Z handling, and
405- // ForegroundChild::wait() needs to be able to react to the
406- // child being stopped.
407417 let _ = sigaction ( Signal :: SIGTSTP , & default) ;
408418 let _ = sigaction ( Signal :: SIGTERM , & default) ;
409419
@@ -412,11 +422,15 @@ mod foreground_pgroup {
412422 }
413423 }
414424
415- pub fn set ( process : & Child , existing_pgrp : u32 ) {
416- set_foreground_pid ( Pid :: from_raw ( process. id ( ) as i32 ) , existing_pgrp) ;
425+ pub fn set ( process : & Child , existing_pgrp : u32 , background : bool ) {
426+ set_foreground_pid (
427+ Pid :: from_raw ( process. id ( ) as i32 ) ,
428+ existing_pgrp,
429+ background,
430+ ) ;
417431 }
418432
419- pub fn set_foreground_pid ( pid : Pid , existing_pgrp : u32 ) {
433+ fn set_foreground_pid ( pid : Pid , existing_pgrp : u32 , background : bool ) {
420434 // Safety: needs to be async-signal-safe.
421435 // `setpgid` and `tcsetpgrp` are async-signal-safe.
422436
@@ -428,7 +442,10 @@ mod foreground_pgroup {
428442 Pid :: from_raw ( existing_pgrp as i32 )
429443 } ;
430444 let _ = unistd:: setpgid ( pid, pgrp) ;
431- let _ = unistd:: tcsetpgrp ( unsafe { stdin_fd ( ) } , pgrp) ;
445+
446+ if !background {
447+ let _ = unistd:: tcsetpgrp ( unsafe { stdin_fd ( ) } , pgrp) ;
448+ }
432449 }
433450
434451 /// Reset the foreground process group to the shell
0 commit comments