mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-06 04:30:28 +00:00
Add thread to kill zombies, when child processes don't die immediately on
SIGHUP. (closes issue #13968) Reported by: eldadran Patches: 20090114__bug13968.diff.txt uploaded by Corydon76 (license 14) Tested by: eldadran git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@171120 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -105,6 +105,8 @@ static char *descrip =
|
|||||||
|
|
||||||
static int agidebug = 0;
|
static int agidebug = 0;
|
||||||
|
|
||||||
|
static pthread_t shaun_of_the_dead_thread = AST_PTHREADT_NULL;
|
||||||
|
|
||||||
#define TONE_BLOCK_SIZE 200
|
#define TONE_BLOCK_SIZE 200
|
||||||
|
|
||||||
/* Max time to connect to an AGI remote host */
|
/* Max time to connect to an AGI remote host */
|
||||||
@@ -119,6 +121,13 @@ enum agi_result {
|
|||||||
AGI_RESULT_HANGUP
|
AGI_RESULT_HANGUP
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct zombie {
|
||||||
|
pid_t pid;
|
||||||
|
AST_LIST_ENTRY(zombie) list;
|
||||||
|
};
|
||||||
|
|
||||||
|
static AST_LIST_HEAD_STATIC(zombies, zombie);
|
||||||
|
|
||||||
static int __attribute__((format(printf, 2, 3))) agi_debug_cli(int fd, char *fmt, ...)
|
static int __attribute__((format(printf, 2, 3))) agi_debug_cli(int fd, char *fmt, ...)
|
||||||
{
|
{
|
||||||
char *stuff;
|
char *stuff;
|
||||||
@@ -1969,7 +1978,26 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
|
|||||||
usleep(1);
|
usleep(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
waitpid(pid, status, WNOHANG);
|
/* This is essentially doing the same as without WNOHANG, except that
|
||||||
|
* it allows the main thread to proceed, even without the child PID
|
||||||
|
* dying immediately (the child may be doing cleanup, etc.). Without
|
||||||
|
* this code, zombie processes accumulate for as long as child
|
||||||
|
* processes exist (which on busy systems may be never, filling up the
|
||||||
|
* process table).
|
||||||
|
*
|
||||||
|
* Note that in trunk, we don't stop interaction at the hangup event
|
||||||
|
* (instead we transparently switch to DeadAGI operation), so this is a
|
||||||
|
* short-lived code addition.
|
||||||
|
*/
|
||||||
|
if (waitpid(pid, status, WNOHANG) == 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fclose(readf);
|
fclose(readf);
|
||||||
return returnstatus;
|
return returnstatus;
|
||||||
@@ -2203,17 +2231,58 @@ static struct ast_cli_entry cli_agi[] = {
|
|||||||
dumpagihtml_help, NULL, &cli_dump_agihtml_deprecated },
|
dumpagihtml_help, NULL, &cli_dump_agihtml_deprecated },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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(&zombies, 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. */
|
||||||
|
poll(NULL, 0, 60000);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int unload_module(void)
|
static int unload_module(void)
|
||||||
{
|
{
|
||||||
|
int res;
|
||||||
|
struct zombie *cur;
|
||||||
ast_module_user_hangup_all();
|
ast_module_user_hangup_all();
|
||||||
ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
|
ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
|
||||||
ast_unregister_application(eapp);
|
ast_unregister_application(eapp);
|
||||||
ast_unregister_application(deadapp);
|
ast_unregister_application(deadapp);
|
||||||
return ast_unregister_application(app);
|
res = ast_unregister_application(app);
|
||||||
|
if (shaun_of_the_dead_thread != AST_PTHREADT_NULL) {
|
||||||
|
pthread_cancel(shaun_of_the_dead_thread);
|
||||||
|
pthread_kill(shaun_of_the_dead_thread, SIGURG);
|
||||||
|
pthread_join(shaun_of_the_dead_thread, NULL);
|
||||||
|
}
|
||||||
|
while ((cur = AST_LIST_REMOVE_HEAD(&zombies, list))) {
|
||||||
|
ast_free(cur);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int load_module(void)
|
static int load_module(void)
|
||||||
{
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
|
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(deadapp, deadagi_exec, deadsynopsis, descrip);
|
||||||
ast_register_application(eapp, eagi_exec, esynopsis, descrip);
|
ast_register_application(eapp, eagi_exec, esynopsis, descrip);
|
||||||
|
Reference in New Issue
Block a user