[Asterisk-code-review] res musiconhold: Add 'kill escalation delay option to classes (asterisk[master])
George Joseph
asteriskteam at digium.com
Tue Jul 11 08:09:11 CDT 2017
George Joseph has uploaded this change for review. ( https://gerrit.asterisk.org/5986
Change subject: res_musiconhold: Add 'kill_escalation_delay option to classes
......................................................................
res_musiconhold: Add 'kill_escalation_delay option to classes
By default, when res_musiconhold reloads or unloads, it sends a HUP
signal to the custom application's process group, waits 100ms, then
sends a TERM signal, waits 100ms, then finally sends a KILL signal.
An application which is interacting with an external device and/or
spawns children of its own may not be able to exit cleanly in the
default times, expecially if sent a KILL signal.
* To allow extra time, the 'kill_escalation_delay' option was added
to the class definition which sets the number of milliseconds to
wait before escalating kill signals. The default remains 100ms.
* The killpg (kill process group) calls were replaced with simple
kills to allow the child process to decide how to terminate any
children rather than us sending signals to all descendants
directly.
Change-Id: Iff70a1a9405685a9021a68416830c0db5158603b
---
M CHANGES
M configs/samples/musiconhold.conf.sample
M res/res_musiconhold.c
3 files changed, 99 insertions(+), 46 deletions(-)
git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/86/5986/1
diff --git a/CHANGES b/CHANGES
index f2760c3..ff36e0a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -18,6 +18,21 @@
been defined.
------------------------------------------------------------------------------
+--- Functionality changes from Asterisk 14.6.0 to Asterisk 14.7.0 ------------
+------------------------------------------------------------------------------
+
+res_musiconhold
+------------------
+ * By default, when res_musiconhold reloads or unloads, it sends a HUP signal
+ to custom applications, waits 100ms, then sends a TERM signal, waits 100ms,
+ then finally sends a KILL signal. An application which is interacting with
+ an external device and/or spawns children of its own may not be able to
+ exit cleanly in the default times, expecially if sent a KILL signal. To
+ allow extra time, the 'kill_escalation_delay' option was added to the
+ class definition which sets the number of milliseconds to wait before
+ escalating kill signals.
+
+------------------------------------------------------------------------------
--- Functionality changes from Asterisk 14.5.0 to Asterisk 14.6.0 ------------
------------------------------------------------------------------------------
diff --git a/configs/samples/musiconhold.conf.sample b/configs/samples/musiconhold.conf.sample
index b2980fc..bd53afa 100644
--- a/configs/samples/musiconhold.conf.sample
+++ b/configs/samples/musiconhold.conf.sample
@@ -97,3 +97,17 @@
;mode=custom
;directory=/var/lib/asterisk/mohmp3
;application=/site/sw/bin/madplay -Q -o raw:- --mono -R 8000 -a -12
+
+; By default, when res_musiconhold reloads or unloads, it sends a HUP signal
+; to custom applications, waits 100ms, then sends a TERM signal, waits 100ms,
+; then finally sends a KILL signal. An application which is interacting with
+; an external device and/or spawns children of its own may not be able to
+; exit cleanly in the default times, expecially if sent a KILL signal. To
+; allow extra time, set 'kill_escalation_delay' to the number of milliseconds
+; to wait before escalating kill signals.
+;[sox_from_device]
+;mode=custom
+;directory=/var/lib/asterisk/mohmp3
+;application=/usr/bin/sox -q -t alsa -c 2 -r 48000 hw:1 -c 1 -r 8000 -t raw -s -
+; Wait 500ms before escalating kill signals
+;kill_escalation_delay=500
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index be50e9c..1d0cef3 100644
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -179,6 +179,8 @@
int pid;
time_t start;
pthread_t thread;
+ /*! Millisecond delay between kill attempts */
+ size_t killdelay;
/*! Source of audio */
int srcfd;
/*! Generic timer */
@@ -680,6 +682,36 @@
return fds[0];
}
+static void killpid(int pid, size_t delay)
+{
+ if (kill(pid, SIGHUP) < 0) {
+ if (errno == ESRCH) {
+ return;
+ }
+ ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process '%d'?!!: %s\n", pid, strerror(errno));
+ } else {
+ ast_debug(1, "Sent HUP to pid %d\n", pid);
+ }
+ usleep(delay);
+ if (kill(pid, SIGTERM) < 0) {
+ if (errno == ESRCH) {
+ return;
+ }
+ ast_log(LOG_WARNING, "Unable to terminate MOH process '%d'?!!: %s\n", pid, strerror(errno));
+ } else {
+ ast_debug(1, "Sent TERM to pid %d\n", pid);
+ }
+ usleep(delay);
+ if (kill(pid, SIGKILL) < 0) {
+ if (errno == ESRCH) {
+ return;
+ }
+ ast_log(LOG_WARNING, "Unable to kill MOH process '%d'?!!: %s\n", pid, strerror(errno));
+ } else {
+ ast_debug(1, "Sent KILL to pid %d\n", pid);
+ }
+}
+
static void *monmp3thread(void *data)
{
#define MOH_MS_INTERVAL 100
@@ -755,28 +787,7 @@
class->srcfd = -1;
pthread_testcancel();
if (class->pid > 1) {
- do {
- if (killpg(class->pid, SIGHUP) < 0) {
- if (errno == ESRCH) {
- break;
- }
- ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno));
- }
- usleep(100000);
- if (killpg(class->pid, SIGTERM) < 0) {
- if (errno == ESRCH) {
- break;
- }
- ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno));
- }
- usleep(100000);
- if (killpg(class->pid, SIGKILL) < 0) {
- if (errno == ESRCH) {
- break;
- }
- ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno));
- }
- } while (0);
+ killpid(class->pid, class->killdelay);
class->pid = 0;
}
} else {
@@ -1357,6 +1368,7 @@
if (class) {
class->format = ao2_bump(ast_format_slin);
class->srcfd = -1;
+ class->killdelay = 100000;
}
return class;
@@ -1615,31 +1627,8 @@
ast_debug(1, "killing %d!\n", class->pid);
stime = time(NULL) + 2;
- pid = class->pid;
+ killpid(class->pid, class->killdelay);
class->pid = 0;
-
- /* Back when this was just mpg123, SIGKILL was fine. Now we need
- * to give the process a reason and time enough to kill off its
- * children. */
- do {
- if (killpg(pid, SIGHUP) < 0) {
- ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno));
- }
- usleep(100000);
- if (killpg(pid, SIGTERM) < 0) {
- if (errno == ESRCH) {
- break;
- }
- ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno));
- }
- usleep(100000);
- if (killpg(pid, SIGKILL) < 0) {
- if (errno == ESRCH) {
- break;
- }
- ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno));
- }
- } while (0);
while ((ast_wait_for_input(class->srcfd, 100) > 0) &&
(bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) {
@@ -1752,6 +1741,40 @@
/* For compatibility with the past, we overwrite any name=name
* with the context [name]. */
ast_copy_string(class->name, cat, sizeof(class->name));
+ for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
+ if (!strcasecmp(var->name, "mode")) {
+ ast_copy_string(class->mode, var->value, sizeof(class->mode));
+ } else if (!strcasecmp(var->name, "directory")) {
+ ast_copy_string(class->dir, var->value, sizeof(class->dir));
+ } else if (!strcasecmp(var->name, "application")) {
+ ast_copy_string(class->args, var->value, sizeof(class->args));
+ } else if (!strcasecmp(var->name, "announcement")) {
+ ast_copy_string(class->announcement, var->value, sizeof(class->announcement));
+ ast_set_flag(class, MOH_ANNOUNCEMENT);
+ } else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value))) {
+ class->digit = *var->value;
+ } else if (!strcasecmp(var->name, "random")) {
+ ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
+ } else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random")) {
+ ast_set_flag(class, MOH_RANDOMIZE);
+ } else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) {
+ ast_set_flag(class, MOH_SORTALPHA);
+ } else if (!strcasecmp(var->name, "format")) {
+ ao2_cleanup(class->format);
+ class->format = ast_format_cache_get(var->value);
+ if (!class->format) {
+ ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
+ class->format = ao2_bump(ast_format_slin);
+ }
+ } else if (!strcasecmp(var->name, "kill_escalation_delay")) {
+ if (sscanf(var->value, "%zu", &class->killdelay) == 1) {
+ class->killdelay *= 1000;
+ } else {
+ ast_log(LOG_WARNING, "kill_escalation_delay '%s' is invalid. Setting to 100ms\n", var->value);
+ class->killdelay = 100000;
+ }
+ }
+ }
if (ast_strlen_zero(class->dir)) {
if (!strcasecmp(class->mode, "custom")) {
@@ -1884,6 +1907,7 @@
ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
if (ast_test_flag(class, MOH_CUSTOM)) {
ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
+ ast_cli(a->fd, "\tKill Escalation Delay: %zu ms\n", class->killdelay / 1000);
}
if (strcasecmp(class->mode, "files")) {
ast_cli(a->fd, "\tFormat: %s\n", ast_format_get_name(class->format));
--
To view, visit https://gerrit.asterisk.org/5986
To unsubscribe, visit https://gerrit.asterisk.org/settings
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: Iff70a1a9405685a9021a68416830c0db5158603b
Gerrit-Change-Number: 5986
Gerrit-PatchSet: 1
Gerrit-Owner: George Joseph <gjoseph at digium.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20170711/b6a2b8a9/attachment.html>
More information about the asterisk-code-review
mailing list