fix: Fish may hang in Linux virtual console

I find that if I have a config.fish consisting of the following two
lines

status --job-control full
. empty.fish

where empty.fish is just an empty file in ~/.config/fish,  Fish will
hang when I attempt to log in on a virtual console (e.g. tty1). If I run
Fish within X11 or with either of those lines commented out,
everything's fine. I think the second line can be any command that cause
Fish to perform a fork().

The fix is pretty simple and just involves replacing getpid() with
getpgrp() in terminal_return_from_job in proc.c. See below for the
detailed explanation. I'm certainly no expert so I would appreciate it
if anyone else can confirm that my fix looks ok.

Here's what causes the bug as far as I can tell:

1. When I login on a virtual console,  /bin/login calls Fish. When Fish
begins executing its process group and the process group controlling the
terminal are both the pid of the /bin/login process.

2. The ". empty.fish" line causes Fish to fork a new process. The new
process creates a new process group and takes control of the terminal
under the name of that process group.

3. When the child process finishes,  the parent prcoess attempts to take
back control of the terminal by setting its controlling process group id
to be its pid.

4. Now there is a mismatch between the process group id of the Fish
shell (= the pid of the /bin/login process) and the process group id
controlling the terminal (= the pid of the Fish shell).
reader_interactive_init detects the mismatch and it thinks that it
doesn't have control of the terminal,  so it hangs as it waits for
control.

My fix just solves the problem in step 3 by having the parent process
correctly reassign control of the terminal to its process group.

Signed-off-by: Grissiom <chaos.proton@gmail.com>
This commit is contained in:
Adam Cozzette 2011-07-28 09:50:39 +08:00 committed by Grissiom
parent c8981c048f
commit e9d1a54983

2
proc.c
View file

@ -931,7 +931,7 @@ static int terminal_give_to_job( job_t *j, int cont )
static int terminal_return_from_job( job_t *j) static int terminal_return_from_job( job_t *j)
{ {
if( tcsetpgrp (0, getpid()) ) if( tcsetpgrp (0, getpgrp()) )
{ {
debug( 1, _( L"Could not return shell to foreground" ) ); debug( 1, _( L"Could not return shell to foreground" ) );
wperror( L"tcsetpgrp" ); wperror( L"tcsetpgrp" );