# HG changeset patch # User Timo Sirainen # Date 1224624526 -10800 # Node ID 3e8f847f68a4bdabb6d437c619ff2d75a05df5f9 # Parent e4d0ce4d342033cfcfe308b718fc63d6a5c89b52 Added API for waiting child processes. diff -r e4d0ce4d3420 -r 3e8f847f68a4 src/lib/Makefile.am --- a/src/lib/Makefile.am Mon Oct 20 20:00:19 2008 +0300 +++ b/src/lib/Makefile.am Wed Oct 22 00:28:46 2008 +0300 @@ -15,6 +15,7 @@ base64.c \ bsearch-insert-pos.c \ buffer.c \ + child-wait.c \ close-keep-errno.c \ compat.c \ crc32.c \ @@ -115,6 +116,7 @@ base64.h \ bsearch-insert-pos.h \ buffer.h \ + child-wait.h \ close-keep-errno.h \ compat.h \ crc32.h \ diff -r e4d0ce4d3420 -r 3e8f847f68a4 src/lib/child-wait.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/child-wait.c Wed Oct 22 00:28:46 2008 +0300 @@ -0,0 +1,108 @@ +/* Copyright (c) 2007-2008 Icecap authors, see the included COPYING file */ + +#include "lib.h" +#include "lib-signals.h" +#include "hash.h" +#include "child-wait.h" + +#include + +struct child_wait { + unsigned int pid_count; + + child_wait_callback_t *callback; + void *context; +}; + +struct hash_table *child_pids; + +#undef child_wait_new_with_pid +struct child_wait * +child_wait_new_with_pid(pid_t pid, child_wait_callback_t *callback, + void *context) +{ + struct child_wait *wait; + + wait = i_new(struct child_wait, 1); + wait->callback = callback; + wait->context = context; + + if (pid != (pid_t)-1) + child_wait_add_pid(wait, pid); + return wait; +} + +void child_wait_free(struct child_wait **_wait) +{ + struct child_wait *wait = *_wait; + struct hash_iterate_context *iter; + void *key, *value; + + *_wait = NULL; + + if (wait->pid_count > 0) { + /* this should be rare, so iterating hash is fast enough */ + iter = hash_iterate_init(child_pids); + while (hash_iterate(iter, &key, &value)) { + if (value == wait) { + hash_remove(child_pids, key); + if (--wait->pid_count == 0) + break; + } + } + hash_iterate_deinit(&iter); + } + + i_free(wait); +} + +void child_wait_add_pid(struct child_wait *wait, pid_t pid) +{ + wait->pid_count++; + hash_insert(child_pids, POINTER_CAST(pid), wait); +} + +void child_wait_remove_pid(struct child_wait *wait, pid_t pid) +{ + wait->pid_count--; + hash_remove(child_pids, POINTER_CAST(pid)); +} + +static void +sigchld_handler(int signo ATTR_UNUSED, void *context ATTR_UNUSED) +{ + struct child_wait_status status; + + while ((status.pid = waitpid(-1, &status.status, WNOHANG)) > 0) { + status.wait = hash_lookup(child_pids, POINTER_CAST(status.pid)); + if (status.wait != NULL) { + child_wait_remove_pid(status.wait, status.pid); + status.wait->callback(&status, status.wait->context); + } + } + + if (status.pid == -1 && errno != EINTR && errno != ECHILD) + i_error("waitpid() failed: %m"); +} + +void child_wait_init(void) +{ + child_pids = hash_create(default_pool, default_pool, 0, NULL, NULL); + + lib_signals_set_handler(SIGCHLD, TRUE, sigchld_handler, NULL); +} + +void child_wait_deinit(void) +{ + struct hash_iterate_context *iter; + void *key, *value; + + lib_signals_unset_handler(SIGCHLD, sigchld_handler, NULL); + + iter = hash_iterate_init(child_pids); + while (hash_iterate(iter, &key, &value)) + i_free(value); + hash_iterate_deinit(&iter); + + hash_destroy(&child_pids); +} diff -r e4d0ce4d3420 -r 3e8f847f68a4 src/lib/child-wait.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/child-wait.h Wed Oct 22 00:28:46 2008 +0300 @@ -0,0 +1,36 @@ +#ifndef CHILD_WAIT_H +#define CHILD_WAIT_H + +struct child_wait_status { + struct child_wait *wait; + + pid_t pid; + int status; +}; + +typedef void child_wait_callback_t(const struct child_wait_status *status, + void *context); + +struct child_wait * +child_wait_new_with_pid(pid_t pid, child_wait_callback_t *callback, + void *context); +#ifdef CONTEXT_TYPE_SAFETY +# define child_wait_new_with_pid(pid, callback, context) \ + ({(void)(1 ? 0 : callback((const struct child_wait_status *)0, \ + context)); \ + child_wait_new_with_pid(pid, (child_wait_callback_t *)callback, context); }) +#else +# define child_wait_new_with_pid(pid, callback, context) \ + child_wait_new_with_pid(pid, (child_wait_callback_t *)callback, context) +#endif +#define child_wait_new(callback, context) \ + child_wait_new_with_pid((pid_t)-1, callback, context) +void child_wait_free(struct child_wait **wait); + +void child_wait_add_pid(struct child_wait *wait, pid_t pid); +void child_wait_remove_pid(struct child_wait *wait, pid_t pid); + +void child_wait_init(void); +void child_wait_deinit(void); + +#endif