1
mirror of https://github.com/mpv-player/mpv synced 2024-09-09 01:16:56 +02:00

Prevent creating zombies

The "run" input command does fork+exec to spawn child processes. But it
doesn't cleanup the child processes, so they are left as zombies until
mpv terminates. Leaving zombie processes around is not very nice, so
employ a simple trick to let pid 1 take care of this: we fork twice, and
when the first fork exits, the second fork becomes orphaned and becomes
pid 1's child. It becomes pid 1's responsibility to cleanup the process.
The advantage is that we don't need extra logic to cleanup the spawned
process, which could have an arbitrary lifetime.

This is e.g. described here: http://yarchive.net/comp/zombie_process.html

Also use _exit() instead of exit(). It's not really sane to run cleanup
handlers (atexit() etc.) inside a forked process.
This commit is contained in:
wm4 2013-11-30 22:47:17 +01:00
parent 95cfe58e3d
commit 9d8573cfe8

View File

@ -23,6 +23,8 @@
#include <stdbool.h>
#include <assert.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <libavutil/avstring.h>
#include <libavutil/common.h>
@ -3028,10 +3030,19 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
char *args[MP_CMD_MAX_ARGS + 1] = {0};
for (int n = 0; n < cmd->nargs; n++)
args[n] = cmd->args[n].v.s;
if (!fork()) {
execvp(args[0], args);
exit(0);
pid_t child = fork();
if (child == 0) {
// Fork twice; the second process will be made child of pid 1 as
// soon as the first process exists, and we don't have to care
// about having to wait for the second process to terminate.
if (fork() == 0) {
execvp(args[0], args);
_exit(0);
}
_exit(0);
}
int st;
while (child != -1 && waitpid(child, &st, 0) < 0 && errno == EINTR) {}
#endif
break;
}