child-wait.c revision 1c7fa51b35231f375998f66d5756f214519218f8
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny#include "lib.h"
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny#include "lib-signals.h"
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny#include "hash.h"
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny#include "child-wait.h"
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny#include <sys/wait.h>
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zelenystruct child_wait {
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny unsigned int pid_count;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny child_wait_callback_t *callback;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny void *context;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny};
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zelenystruct hash_table *child_pids;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny#undef child_wait_new_with_pid
f26c954658dfd7461f290f0b5d924951a6db219aJan Zelenystruct child_wait *
f26c954658dfd7461f290f0b5d924951a6db219aJan Zelenychild_wait_new_with_pid(pid_t pid, child_wait_callback_t *callback,
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny void *context)
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny{
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny struct child_wait *wait;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny wait = i_new(struct child_wait, 1);
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny wait->callback = callback;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny wait->context = context;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny if (pid != (pid_t)-1)
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny child_wait_add_pid(wait, pid);
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny return wait;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny}
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zelenyvoid child_wait_free(struct child_wait **_wait)
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny{
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny struct child_wait *wait = *_wait;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny struct hash_iterate_context *iter;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny void *key, *value;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny *_wait = NULL;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny if (wait->pid_count > 0) {
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny /* this should be rare, so iterating hash is fast enough */
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny iter = hash_table_iterate_init(child_pids);
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny while (hash_table_iterate(iter, &key, &value)) {
684d1b48b5582a1bf7812b8c3c663592dc6dfed9Pavel Březina if (value == wait) {
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny hash_table_remove(child_pids, key);
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny if (--wait->pid_count == 0)
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny break;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny }
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny }
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny hash_table_iterate_deinit(&iter);
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny }
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny i_free(wait);
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny}
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zelenyvoid child_wait_add_pid(struct child_wait *wait, pid_t pid)
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny{
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny wait->pid_count++;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny hash_table_insert(child_pids, POINTER_CAST(pid), wait);
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny}
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zelenyvoid child_wait_remove_pid(struct child_wait *wait, pid_t pid)
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny{
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny wait->pid_count--;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny hash_table_remove(child_pids, POINTER_CAST(pid));
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny}
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zelenystatic void
f26c954658dfd7461f290f0b5d924951a6db219aJan Zelenysigchld_handler(const siginfo_t *si ATTR_UNUSED, void *context ATTR_UNUSED)
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny{
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny struct child_wait_status status;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny while ((status.pid = waitpid(-1, &status.status, WNOHANG)) > 0) {
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny status.wait = hash_table_lookup(child_pids,
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny POINTER_CAST(status.pid));
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny if (status.wait != NULL) {
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny child_wait_remove_pid(status.wait, status.pid);
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny status.wait->callback(&status, status.wait->context);
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny }
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny }
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny if (status.pid == -1 && errno != EINTR && errno != ECHILD)
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny i_error("waitpid() failed: %m");
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny}
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zelenyvoid child_wait_init(void)
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny{
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny child_pids = hash_table_create(default_pool, default_pool, 0,
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny NULL, NULL);
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
684d1b48b5582a1bf7812b8c3c663592dc6dfed9Pavel Březina lib_signals_set_handler(SIGCHLD, TRUE, sigchld_handler, NULL);
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny}
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zelenyvoid child_wait_deinit(void)
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny{
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny struct hash_iterate_context *iter;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny void *key, *value;
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny lib_signals_unset_handler(SIGCHLD, sigchld_handler, NULL);
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny iter = hash_table_iterate_init(child_pids);
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny while (hash_table_iterate(iter, &key, &value))
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny i_free(value);
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny hash_table_iterate_deinit(&iter);
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny hash_table_destroy(&child_pids);
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny}
f26c954658dfd7461f290f0b5d924951a6db219aJan Zeleny