Index: res/res_agi.c =================================================================== --- res/res_agi.c (revision 159245) +++ res/res_agi.c (working copy) @@ -105,6 +105,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 */ @@ -119,6 +121,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_malloc(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; @@ -1945,7 +1965,9 @@ usleep(1); } } - waitpid(pid, status, WNOHANG); + if (waitpid(pid, status, WNOHANG) == 0) { + add_zombie(pid); + } } fclose(readf); return returnstatus; @@ -2179,17 +2201,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);