Commit 7c3370d4fe3fa6cda8655f109e4659afc8ca4269
Committed by
Mark McLoughlin
1 parent
c27ff608
slirp: Avoid zombie processes after fork_exec
Slirp uses fork_exec for spawning service processes, and QEMU uses this for running smbd. As SIGCHLD is not handled, these processes become zombies on termination. Fix this by installing a proper signal handler, but also make sure we disable the signal while waiting on forked network setup/shutdown scripts. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Showing
2 changed files
with
45 additions
and
28 deletions
net.c
@@ -1134,38 +1134,46 @@ static int tap_open(char *ifname, int ifname_size) | @@ -1134,38 +1134,46 @@ static int tap_open(char *ifname, int ifname_size) | ||
1134 | 1134 | ||
1135 | static int launch_script(const char *setup_script, const char *ifname, int fd) | 1135 | static int launch_script(const char *setup_script, const char *ifname, int fd) |
1136 | { | 1136 | { |
1137 | + sigset_t oldmask, mask; | ||
1137 | int pid, status; | 1138 | int pid, status; |
1138 | char *args[3]; | 1139 | char *args[3]; |
1139 | char **parg; | 1140 | char **parg; |
1140 | 1141 | ||
1141 | - /* try to launch network script */ | ||
1142 | - pid = fork(); | ||
1143 | - if (pid >= 0) { | ||
1144 | - if (pid == 0) { | ||
1145 | - int open_max = sysconf (_SC_OPEN_MAX), i; | ||
1146 | - for (i = 0; i < open_max; i++) | ||
1147 | - if (i != STDIN_FILENO && | ||
1148 | - i != STDOUT_FILENO && | ||
1149 | - i != STDERR_FILENO && | ||
1150 | - i != fd) | ||
1151 | - close(i); | ||
1152 | - | ||
1153 | - parg = args; | ||
1154 | - *parg++ = (char *)setup_script; | ||
1155 | - *parg++ = (char *)ifname; | ||
1156 | - *parg++ = NULL; | ||
1157 | - execv(setup_script, args); | ||
1158 | - _exit(1); | ||
1159 | - } | ||
1160 | - while (waitpid(pid, &status, 0) != pid); | ||
1161 | - if (!WIFEXITED(status) || | ||
1162 | - WEXITSTATUS(status) != 0) { | ||
1163 | - fprintf(stderr, "%s: could not launch network script\n", | ||
1164 | - setup_script); | ||
1165 | - return -1; | 1142 | + sigemptyset(&mask); |
1143 | + sigaddset(&mask, SIGCHLD); | ||
1144 | + sigprocmask(SIG_BLOCK, &mask, &oldmask); | ||
1145 | + | ||
1146 | + /* try to launch network script */ | ||
1147 | + pid = fork(); | ||
1148 | + if (pid == 0) { | ||
1149 | + int open_max = sysconf(_SC_OPEN_MAX), i; | ||
1150 | + | ||
1151 | + for (i = 0; i < open_max; i++) { | ||
1152 | + if (i != STDIN_FILENO && | ||
1153 | + i != STDOUT_FILENO && | ||
1154 | + i != STDERR_FILENO && | ||
1155 | + i != fd) { | ||
1156 | + close(i); | ||
1166 | } | 1157 | } |
1167 | } | 1158 | } |
1168 | - return 0; | 1159 | + parg = args; |
1160 | + *parg++ = (char *)setup_script; | ||
1161 | + *parg++ = (char *)ifname; | ||
1162 | + *parg++ = NULL; | ||
1163 | + execv(setup_script, args); | ||
1164 | + _exit(1); | ||
1165 | + } else if (pid > 0) { | ||
1166 | + while (waitpid(pid, &status, 0) != pid) { | ||
1167 | + /* loop */ | ||
1168 | + } | ||
1169 | + sigprocmask(SIG_SETMASK, &oldmask, NULL); | ||
1170 | + | ||
1171 | + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { | ||
1172 | + return 0; | ||
1173 | + } | ||
1174 | + } | ||
1175 | + fprintf(stderr, "%s: could not launch network script\n", setup_script); | ||
1176 | + return -1; | ||
1169 | } | 1177 | } |
1170 | 1178 | ||
1171 | static int net_tap_init(VLANState *vlan, const char *model, | 1179 | static int net_tap_init(VLANState *vlan, const char *model, |
vl.c
@@ -4783,7 +4783,12 @@ static void termsig_handler(int signal) | @@ -4783,7 +4783,12 @@ static void termsig_handler(int signal) | ||
4783 | qemu_system_shutdown_request(); | 4783 | qemu_system_shutdown_request(); |
4784 | } | 4784 | } |
4785 | 4785 | ||
4786 | -static void termsig_setup(void) | 4786 | +static void sigchld_handler(int signal) |
4787 | +{ | ||
4788 | + waitpid(-1, NULL, WNOHANG); | ||
4789 | +} | ||
4790 | + | ||
4791 | +static void sighandler_setup(void) | ||
4787 | { | 4792 | { |
4788 | struct sigaction act; | 4793 | struct sigaction act; |
4789 | 4794 | ||
@@ -4792,6 +4797,10 @@ static void termsig_setup(void) | @@ -4792,6 +4797,10 @@ static void termsig_setup(void) | ||
4792 | sigaction(SIGINT, &act, NULL); | 4797 | sigaction(SIGINT, &act, NULL); |
4793 | sigaction(SIGHUP, &act, NULL); | 4798 | sigaction(SIGHUP, &act, NULL); |
4794 | sigaction(SIGTERM, &act, NULL); | 4799 | sigaction(SIGTERM, &act, NULL); |
4800 | + | ||
4801 | + act.sa_handler = sigchld_handler; | ||
4802 | + act.sa_flags = SA_NOCLDSTOP; | ||
4803 | + sigaction(SIGCHLD, &act, NULL); | ||
4795 | } | 4804 | } |
4796 | 4805 | ||
4797 | #endif | 4806 | #endif |
@@ -5918,7 +5927,7 @@ int main(int argc, char **argv, char **envp) | @@ -5918,7 +5927,7 @@ int main(int argc, char **argv, char **envp) | ||
5918 | 5927 | ||
5919 | #ifndef _WIN32 | 5928 | #ifndef _WIN32 |
5920 | /* must be after terminal init, SDL library changes signal handlers */ | 5929 | /* must be after terminal init, SDL library changes signal handlers */ |
5921 | - termsig_setup(); | 5930 | + sighandler_setup(); |
5922 | #endif | 5931 | #endif |
5923 | 5932 | ||
5924 | /* Maintain compatibility with multiple stdio monitors */ | 5933 | /* Maintain compatibility with multiple stdio monitors */ |