aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
authortilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2011-01-19 20:13:24 +0000
committertilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2011-01-19 20:13:24 +0000
commit789eabecddf45412756d1a8e18bfc53cca1d3918 (patch)
tree30a02378ce6cebe02a36b8b2e16ed97abe6dfaf9 /main
parentd9be7567d1b18eea0aad9ffbffe1be3b4c1d1055 (diff)
Kill zombies.
When we ast_safe_fork() with a non-zero argument, we're expected to reap our own zombies. On a zero argument, however, the zombies are only reaped when there aren't any non-zero forked children alive. At other times, we accumulate zombies. This code is forward ported from res_agi in 1.4, so that forked children are always reaped, thus preventing an accumulation of zombie processes. (closes issue #18515) Reported by: ernied Patches: 20101221__issue18515.diff.txt uploaded by tilghman (license 14) Tested by: ernied git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.6.2@302599 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main')
-rw-r--r--main/app.c53
1 files changed, 52 insertions, 1 deletions
diff --git a/main/app.c b/main/app.c
index a7fba76f0..3fbcfd72d 100644
--- a/main/app.c
+++ b/main/app.c
@@ -36,8 +36,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/time.h> /* for getrlimit(2) */
#include <sys/resource.h> /* for getrlimit(2) */
#include <stdlib.h> /* for closefrom(3) */
-#ifndef HAVE_CLOSEFROM
#include <sys/types.h>
+#include <sys/wait.h> /* for waitpid(2) */
+#ifndef HAVE_CLOSEFROM
#include <dirent.h> /* for opendir(3) */
#endif
#ifdef HAVE_CAP
@@ -58,6 +59,41 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
AST_THREADSTORAGE_PUBLIC(ast_str_thread_global_buf);
+static pthread_t shaun_of_the_dead_thread = AST_PTHREADT_NULL;
+
+struct zombie {
+ pid_t pid;
+ AST_LIST_ENTRY(zombie) list;
+};
+
+static AST_LIST_HEAD_STATIC(zombies, zombie);
+
+static void *shaun_of_the_dead(void *data)
+{
+ struct zombie *cur;
+ int status;
+ for (;;) {
+ if (!AST_LIST_EMPTY(&zombies)) {
+ /* Don't allow cancellation while we have a lock. */
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+ AST_LIST_LOCK(&zombies);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&zombies, cur, list) {
+ if (waitpid(cur->pid, &status, WNOHANG) != 0) {
+ AST_LIST_REMOVE_CURRENT(list);
+ ast_free(cur);
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END
+ AST_LIST_UNLOCK(&zombies);
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ }
+ pthread_testcancel();
+ /* Wait for 60 seconds, without engaging in a busy loop. */
+ ast_poll(NULL, 0, AST_LIST_FIRST(&zombies) ? 5000 : 60000);
+ }
+ return NULL;
+}
+
#define AST_MAX_FORMATS 10
@@ -2054,6 +2090,21 @@ int ast_safe_fork(int stop_reaper)
if (pid != 0) {
/* Fork failed or parent */
pthread_sigmask(SIG_SETMASK, &old_set, NULL);
+ if (!stop_reaper && pid > 0) {
+ struct zombie *cur = ast_calloc(1, sizeof(*cur));
+ if (cur) {
+ cur->pid = pid;
+ AST_LIST_LOCK(&zombies);
+ AST_LIST_INSERT_TAIL(&zombies, cur, list);
+ AST_LIST_UNLOCK(&zombies);
+ if (shaun_of_the_dead_thread == AST_PTHREADT_NULL) {
+ if (ast_pthread_create_background(&shaun_of_the_dead_thread, NULL, shaun_of_the_dead, NULL)) {
+ ast_log(LOG_ERROR, "Shaun of the Dead wants to kill zombies, but can't?!!\n");
+ shaun_of_the_dead_thread = AST_PTHREADT_NULL;
+ }
+ }
+ }
+ }
return pid;
} else {
/* Child */