We normally do the writing job to a FIFO file in background using a control operator &. Something like below.

if [ ! -p "/tmp/mysqld.init" ]; then
    mkfifo /tmp/mysqld.init

echo "something" > /tmp/mysqld.init &

exec mysqld --init-file=/tmp/mysqld.init

But when the fifo file is readout the echo process get a zombie process. How can it be avoided ?

Note This script is a docker entrypoint script and I don't have a proper zombie handler. Mysqld always takes the pid 1. Something like below.

    1     0 mysql    S     383m  19%   0   0% mysqld --init-file=/tmp/mysqld.init
   40     0 root     R     1532   0%   1   0% top
    7     1 root     Z        0   0%   0   0% [entrypoint.sh]

Probably I can use tini an init system for docker but without it how can it be achieved ? Double fork ?

  • You can not ups exec, but this will use up a process. Alternatively just let it happen. There is little cost in a zombie process. init is usually the reaper of lost children. As mysql is taking the role of init, this will not happen. It will probably be cheapest to just let it be a zombi. And no more than the cost of the un-used fifo that is left lying around. – ctrl-alt-delor Jan 21 '19 at 22:48

The problem is surprisingly more complicated than most people would expect.

The short answer is that you need to use init, or write a replacement for init that implements reaping and downstream signals propagation, or find a new way to pass data to mysqld, or find a way to live with it (which requires understanding and limiting your zombie creation rate).

zombie processes arise when their exit status is not collected (reaped) by the parent. exec replaces the current process (a shell) with mysqld, which is not expecting to inherit child processes.

If you start mysqld in the background, and let the shell script remain to reap children, it also needs to handle propagating received signals to mysqld and waiting for them to respond. Failing to do so will cause mysql to be un-gracefully terminated when the shell script exits. This reaping and propagation is normally the job of init.

You can make the echo exit immediately by opening a handle for read, like this:

echo "something" > /tmp/fifo &
exec 3< /tmp/fifo

... but that creates a new problem: normally echo would close the fifo, and now it can't: it exits too soon. That means mysql will block when reading it. It's possible to do non-blocking reads and implement timeouts and all that, but we can assume mysql doesn't, because it probably expects --init-file to behave like a regular file.

The last option is to live with it. If we're talking about 1 process or 100, that's fine. But the process table is finite and each zombie consumes an entry in it. If you don't manage the zombie count, and the process table fills, you can't create any new processes.

The blog post I linked has a lot of good detail and plugs a small init replacement, created by the author, to solve your exact problem.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.