The default `sh` shell does not reap backgrounded processes if sitting idle, and killed backgrounded processes are not reaped until a new command is executed or enter is pressed at the tty. For example, ``` $ cat <CTRL-Z> [1] + Suspended cat $ ``` Now in another terminal or in an SSH session: ``` $ killall -9 cat ``` The PID associated with cat is turned into a zombie as the shell does not reap the killed instance. The only way to trigger reaping would be to attach to the tty session where the process was initially backgrounded and hit <ENTER>: ``` $ cat # resuming from first segment above $ <ENTER> [1] Killed cat $ ``` Solution: `waitpid(2)` should be used to asynchronously detect the exit of backgrounded child processes.
If this is to be fixed, waitpid() alone does not suffice, since it does not let you wait for either terminal input or a process termination. It is necessary to have a SIGCHLD signal handler (either directly or via pselect(2)). Due to limitations in libedit's API, the signal handler could not do much more than reap the zombie and register this in the struct job. This does not help much except system administrators that insist on zombies being reaped quickly. Things like a proper 'set -b' (notify about job state at any time) would require some way to execute a handler function in a defined environment and to redraw the pending input.