Merge pull request #688 from giuseppe/conmon-do-not-leave-zombies
conmon: use waitpid to wait for terminated processes
This commit is contained in:
commit
4cce851851
1 changed files with 63 additions and 3 deletions
|
@ -550,6 +550,45 @@ static bool read_stdio(int fd, stdpipe_t pipe, bool *eof)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void on_sigchld(G_GNUC_UNUSED int signal)
|
||||||
|
{
|
||||||
|
raise (SIGUSR1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_child_processes(GHashTable *pid_to_handler)
|
||||||
|
{
|
||||||
|
void (*cb) (GPid, int, gpointer);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int status;
|
||||||
|
pid_t pid = waitpid(-1, &status, WNOHANG);
|
||||||
|
|
||||||
|
if (pid < 0 && errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if (pid < 0 && errno == ECHILD) {
|
||||||
|
g_main_loop_quit (main_loop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (pid < 0)
|
||||||
|
pexit("Failed to read child process status");
|
||||||
|
|
||||||
|
if (pid == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* If we got here, pid > 0, so we have a valid pid to check. */
|
||||||
|
cb = g_hash_table_lookup(pid_to_handler, &pid);
|
||||||
|
if (cb)
|
||||||
|
cb(pid, status, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean on_sigusr1_cb(gpointer user_data)
|
||||||
|
{
|
||||||
|
GHashTable *pid_to_handler = (GHashTable *) user_data;
|
||||||
|
check_child_processes (pid_to_handler);
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean stdio_cb(int fd, GIOCondition condition, gpointer user_data)
|
static gboolean stdio_cb(int fd, GIOCondition condition, gpointer user_data)
|
||||||
{
|
{
|
||||||
stdpipe_t pipe = GPOINTER_TO_INT(user_data);
|
stdpipe_t pipe = GPOINTER_TO_INT(user_data);
|
||||||
|
@ -1221,20 +1260,39 @@ int main(int argc, char *argv[])
|
||||||
close(slavefd_stdout);
|
close(slavefd_stdout);
|
||||||
close(slavefd_stderr);
|
close(slavefd_stderr);
|
||||||
|
|
||||||
|
/* Map pid to its handler. */
|
||||||
|
GHashTable *pid_to_handler = g_hash_table_new (g_int_hash, g_int_equal);
|
||||||
|
g_hash_table_insert (pid_to_handler, &create_pid, runtime_exit_cb);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Glib does not support SIGCHLD so use SIGUSR1 with the same semantic. We will
|
||||||
|
* catch SIGCHLD and raise(SIGUSR1) in the signal handler.
|
||||||
|
*/
|
||||||
|
g_unix_signal_add (SIGUSR1, on_sigusr1_cb, pid_to_handler);
|
||||||
|
|
||||||
|
if (signal(SIGCHLD, on_sigchld) == SIG_ERR)
|
||||||
|
pexit("Failed to set handler for SIGCHLD");
|
||||||
|
|
||||||
ninfo("about to waitpid: %d", create_pid);
|
ninfo("about to waitpid: %d", create_pid);
|
||||||
if (csname != NULL) {
|
if (csname != NULL) {
|
||||||
guint terminal_watch = g_unix_fd_add (console_socket_fd, G_IO_IN, terminal_accept_cb, csname);
|
guint terminal_watch = g_unix_fd_add (console_socket_fd, G_IO_IN, terminal_accept_cb, csname);
|
||||||
g_child_watch_add (create_pid, runtime_exit_cb, NULL);
|
/* Process any SIGCHLD we may have missed before the signal handler was in place. */
|
||||||
|
check_child_processes (pid_to_handler);
|
||||||
g_main_loop_run (main_loop);
|
g_main_loop_run (main_loop);
|
||||||
g_source_remove (terminal_watch);
|
g_source_remove (terminal_watch);
|
||||||
} else {
|
} else {
|
||||||
|
int ret;
|
||||||
/* Wait for our create child to exit with the return code. */
|
/* Wait for our create child to exit with the return code. */
|
||||||
if (waitpid(create_pid, &runtime_status, 0) < 0) {
|
do
|
||||||
|
ret = waitpid(create_pid, &runtime_status, 0);
|
||||||
|
while (ret < 0 && errno == EINTR);
|
||||||
|
if (ret < 0) {
|
||||||
int old_errno = errno;
|
int old_errno = errno;
|
||||||
kill(create_pid, SIGKILL);
|
kill(create_pid, SIGKILL);
|
||||||
errno = old_errno;
|
errno = old_errno;
|
||||||
pexit("Failed to wait for `runtime %s`", opt_exec ? "exec" : "create");
|
pexit("Failed to wait for `runtime %s`", opt_exec ? "exec" : "create");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WIFEXITED(runtime_status) || WEXITSTATUS(runtime_status) != 0) {
|
if (!WIFEXITED(runtime_status) || WEXITSTATUS(runtime_status) != 0) {
|
||||||
|
@ -1266,6 +1324,8 @@ int main(int argc, char *argv[])
|
||||||
container_pid = atoi(contents);
|
container_pid = atoi(contents);
|
||||||
ninfo("container PID: %d", container_pid);
|
ninfo("container PID: %d", container_pid);
|
||||||
|
|
||||||
|
g_hash_table_insert (pid_to_handler, &container_pid, container_exit_cb);
|
||||||
|
|
||||||
/* Setup endpoint for attach */
|
/* Setup endpoint for attach */
|
||||||
_cleanup_free_ char *attach_symlink_dir_path = NULL;
|
_cleanup_free_ char *attach_symlink_dir_path = NULL;
|
||||||
if (!opt_exec) {
|
if (!opt_exec) {
|
||||||
|
@ -1294,7 +1354,7 @@ int main(int argc, char *argv[])
|
||||||
g_timeout_add_seconds (opt_timeout, timeout_cb, NULL);
|
g_timeout_add_seconds (opt_timeout, timeout_cb, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_child_watch_add (container_pid, container_exit_cb, NULL);
|
check_child_processes(pid_to_handler);
|
||||||
|
|
||||||
g_main_loop_run (main_loop);
|
g_main_loop_run (main_loop);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue