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 */ |