|
|
|
|
@ -105,6 +105,8 @@ static char *descrip =
|
|
|
|
|
|
|
|
|
|
static int agidebug = 0;
|
|
|
|
|
|
|
|
|
|
static pthread_t shaun_of_the_dead_thread = AST_PTHREADT_NULL;
|
|
|
|
|
|
|
|
|
|
#define TONE_BLOCK_SIZE 200
|
|
|
|
|
|
|
|
|
|
/* Max time to connect to an AGI remote host */
|
|
|
|
|
@ -119,6 +121,13 @@ enum agi_result {
|
|
|
|
|
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, ...)
|
|
|
|
|
{
|
|
|
|
|
char *stuff;
|
|
|
|
|
@ -1969,7 +1978,26 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
|
|
|
|
|
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);
|
|
|
|
|
return returnstatus;
|
|
|
|
|
@ -2203,17 +2231,58 @@ static struct ast_cli_entry cli_agi[] = {
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
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 (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)
|
|
|
|
|
{
|
|
|
|
|
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_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
|
|
|
|
|
ast_register_application(eapp, eagi_exec, esynopsis, descrip);
|
|
|
|
|
|