`fish` process is eating 100% CPU #422

Closed
lunixbochs opened this Issue Dec 3, 2012 · 12 comments

Comments

Projects
None yet
3 participants
Contributor

lunixbochs commented Dec 3, 2012

dtruss shows it's looping on a kill()

ioctl(0x0, 0x4004667A, 0x7FFF57A8E4A4)       = 0 0
ioctl(0x0, 0x40047477, 0x7FFF57A8E4C4)       = -1 Err#25
kill(0xFFFF0C40, 0x15, 0x1)      = 0 0
ioctl(0x0, 0x4004667A, 0x7FFF57A8E4A4)       = 0 0
ioctl(0x0, 0x40047477, 0x7FFF57A8E4C4)       = -1 Err#25
kill(0xFFFF0C40, 0x15, 0x1)      = 0 0
ioctl(0x0, 0x4004667A, 0x7FFF57A8E4A4)       = 0 0
ioctl(0x0, 0x40047477, 0x7FFF57A8E4C4)       = -1 Err#25
kill(0xFFFF0C40, 0x15, 0x1)      = 0 0
ioctl(0x0, 0x4004667A, 0x7FFF57A8E4A4)       = 0 0
ioctl(0x0, 0x40047477, 0x7FFF57A8E4C4)       = -1 Err#25
kill(0xFFFF0C40, 0x15, 0x1)      = 0 0
ioctl(0x0, 0x4004667A, 0x7FFF57A8E4A4)       = 0 0
ioctl(0x0, 0x40047477, 0x7FFF57A8E4C4)       = -1 Err#25

GDB backtrace:

#0  0x00007fff815a1d46 in __kill ()
#1  0x000000010822c843 in reader_interactive_init ()
#2  0x0000000108231924 in reader_push ()
#3  0x000000010823213e in read_i ()
#4  0x0000000108232bd8 in reader_read ()
#5  0x000000010829e09f in main ()
Contributor

lunixbochs commented Dec 3, 2012

The parent process id is 1, which probably means the parent process of fish terminated but fish did not.

Looks like this is happening in reader.cpp:reader_interactive_init():

/*
  Ok, signal handlers are taken out of the picture. Stop ourself in a loop
  until we are in control of the terminal.
 */
while (tcgetpgrp(0) != shell_pgid)
{
    killpg(shell_pgid, SIGTTIN);
}
Contributor

fosskers commented Dec 3, 2012

I get this every once and a while too.

Owner

ridiculousfish commented Dec 5, 2012

I can reproduce this by having a process that forks fish off then dies.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void) {
    printf("I am %d\n", getpid());
    int ret = fork();
    if (ret == 0) {
        /* Child */
        execl("./lfish", "lfish", NULL);
    } else {
        /* Parent */
        printf("Child is %d\n", ret);
        exit(0);
    }
    return 0;
}
Owner

ridiculousfish commented Dec 5, 2012

bash and zsh have the same problem - my goodness!

Contributor

lunixbochs commented Dec 5, 2012

Looks like a ton of shells do this. Maybe bail if ppid == 1?

Contributor

lunixbochs commented Dec 5, 2012

EIO is fine if the stdin read fails, but what if it works or hangs? Aren't we just trying to detect whether we're an orphaned process?

Owner

ridiculousfish commented Dec 5, 2012

Exactly...I don't know of a better way to detect orphaned processes. If you do, please share it!

It might be better to read from /dev/tty instead of stdin, in case the shell was invoked with a redirect.

Owner

ridiculousfish commented Dec 5, 2012

Another idea: kill(0) the parent group ID. If it fails, that means the parent process is gone, and therefore I am orphaned.

Contributor

fosskers commented Dec 5, 2012

+1

Owner

ridiculousfish commented Dec 5, 2012

Here's my plan:

  1. Loop sending SIGTTIN to ourselves until our process group owns the terminal device
  2. Occasionally, try to signal the process whose pid matches our group ID. If that fails with ESRCH, assume we're orphaned. I believe this will usually work.
  3. Less often, try a non-blocking read of one byte from /dev/tty. If that fails with EIO, assume we're orphaned. If it succeeds, drop the byte on the floor.
  4. After 4k loops with no success, assume we're orphaned.
  5. If we're orphaned, print a polite message about how you're just letting orphans die, and then exit.
Owner

ridiculousfish commented Dec 5, 2012

To git@github.com:fish-shell/fish-shell.git
19edddd..40ec230 master -> master

(Check out my quads)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment