Index: res/res_agi.c
===================================================================
--- res/res_agi.c	(revision 168717)
+++ res/res_agi.c	(working copy)
@@ -104,6 +104,8 @@
 
 static int agidebug = 0;
 
+static pthread_t grim_reaper_thread = AST_PTHREADT_NULL;
+
 #define TONE_BLOCK_SIZE 200
 
 /* Max time to connect to an AGI remote host */
@@ -118,6 +120,24 @@
 	AGI_RESULT_HANGUP
 };
 
+struct zombie {
+	pid_t pid;
+	AST_LIST_ENTRY(zombie) list;
+};
+
+static AST_LIST_HEAD_STATIC(zombies, zombie);
+
+static void add_zombie(pid_t pid)
+{
+	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);
+	}
+}
+
 static int agi_debug_cli(int fd, char *fmt, ...)
 {
 	char *stuff;
@@ -1940,7 +1960,9 @@
 				usleep(1);
 			}
 		}
-		waitpid(pid, status, WNOHANG);
+		if (waitpid(pid, status, WNOHANG) == 0) {
+			add_zombie(pid);
+		}
 	}
 	fclose(readf);
 	return returnstatus;
@@ -2174,17 +2196,54 @@
 	dumpagihtml_help, NULL, &cli_dump_agihtml_deprecated },
 };
 
+static void *grim_reaper(void *data)
+{
+	struct zombie *cur;
+	int status;
+	for (;;) {
+		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(&zombies, list);
+				ast_free(cur);
+			}
+		}
+		AST_LIST_TRAVERSE_SAFE_END
+		AST_LIST_UNLOCK(&zombies);
+		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+		pthread_testcancel();
+		poll(NULL, 0, 60000);
+	}
+	return NULL;
+}
+
 static int unload_module(void)
 {
+	int res;
+	struct zombie *cur;
 	ast_module_user_hangup_all();
 	ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
 	ast_unregister_application(eapp);
 	ast_unregister_application(deadapp);
-	return ast_unregister_application(app);
+	res = ast_unregister_application(app);
+	if (grim_reaper_thread != AST_PTHREADT_NULL) {
+		pthread_cancel(grim_reaper_thread);
+		pthread_kill(grim_reaper_thread, SIGURG);
+		pthread_join(grim_reaper_thread, NULL);
+	}
+	while ((cur = AST_LIST_REMOVE_HEAD(&zombies, list))) {
+		ast_free(cur);
+	}
+	return res;
 }
 
 static int load_module(void)
 {
+	if (ast_pthread_create_background(&grim_reaper_thread, NULL, grim_reaper, NULL)) {
+		ast_log(LOG_ERROR, "D'oh!  Can't start the grim reaper?!!\n");
+		grim_reaper_thread = AST_PTHREADT_NULL;
+	}
 	ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
 	ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
 	ast_register_application(eapp, eagi_exec, esynopsis, descrip);

