aboutsummaryrefslogtreecommitdiffstats
path: root/res/res_musiconhold.c
diff options
context:
space:
mode:
authorkpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b>2005-07-11 21:42:25 +0000
committerkpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b>2005-07-11 21:42:25 +0000
commit84b415519da334810e16dc37a6987e4f756f33de (patch)
tree4c2d56418de99e96a64275842d223869e14f423a /res/res_musiconhold.c
parentcfd662aa15cd7fc8ce006a75140c345da44e1253 (diff)
fix threading portability problem with FreeBSD (bug #4532)
ensure that all mpg123 child processes get killed when the parent is killed (bug #4532) git-svn-id: http://svn.digium.com/svn/asterisk/trunk@6086 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'res/res_musiconhold.c')
-rwxr-xr-xres/res_musiconhold.c56
1 files changed, 38 insertions, 18 deletions
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index 07ba5fa08..8802562fb 100755
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -402,19 +402,44 @@ static int spawn_mp3(struct mohclass *class)
ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
return -1;
}
- if (!class->pid) {
- int x;
- close(fds[0]);
- /* Stdout goes to pipe */
- dup2(fds[1], STDOUT_FILENO);
- /* Close unused file descriptors */
- for (x=3;x<8192;x++) {
- if (-1 != fcntl(x, F_GETFL)) {
- close(x);
+ if (class->pid != 0) { /* parent */
+ close(fds[1]);
+ return fds[0];
+ } else {
+ /* Child */
+ int i;
+ /*
+ * On BSD systems with userland pthreads libraries, we need
+ * to call fcntl() _before_ close() to avoid resetting
+ * O_NONBLOCK on the internal descriptors.
+ * It should not harm in other systems.
+ *
+ * After that, close the descriptors not needed in the child.
+ * It is also important that we do not share descriptors
+ * with the child process or it could change their blocking
+ * state and give trouble in the thread scheduling.
+ * Here, parent and child are connected only through the
+ * endpoints of a pipe, so they share no descriptors.
+ */
+ for (i=0; i < getdtablesize(); i++) {
+ long fl = fcntl(i, F_GETFL);
+ if (fl != -1 && i != fds[1]) {
+ /* open and must be closed in the child */
+ fcntl(i, F_SETFL, O_NONBLOCK | fl);
+ close(i);
}
}
- /* Child */
+ /* Stdout in the child goes to pipe */
+ dup2(fds[1], STDOUT_FILENO);
chdir(class->dir);
+ /*
+ * mpg123 may fork children to be more responsive, and we
+ * want to kill them all when we exit. To do so we set
+ * the process group id of mpg123 and children to a different
+ * value than the asterisk process so we can kill all at once.
+ * So remember, class->pid is really class->pgid!
+ */
+ setpgid(0, getpid());
if (ast_test_flag(class, MOH_CUSTOM)) {
execv(argv[0], argv);
} else {
@@ -425,14 +450,9 @@ static int spawn_mp3(struct mohclass *class)
/* Check PATH as a last-ditch effort */
execvp("mpg123", argv);
}
- ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
- close(fds[1]);
exit(1);
- } else {
- /* Parent */
- close(fds[1]);
+ return 0; /* unreached */
}
- return fds[0];
}
static void *monmp3thread(void *data)
@@ -511,7 +531,7 @@ static void *monmp3thread(void *data)
close(class->srcfd);
class->srcfd = -1;
if (class->pid) {
- kill(class->pid, SIGKILL);
+ killpg(class->pid, SIGKILL); /* pgid! */
class->pid = 0;
}
} else
@@ -957,7 +977,7 @@ static void ast_moh_destroy(void)
stime = time(NULL) + 2;
pid = moh->pid;
moh->pid = 0;
- kill(pid, SIGKILL);
+ killpg(pid, SIGKILL); /* pgid! */
while ((ast_wait_for_input(moh->srcfd, 100) > -1) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime) {
tbytes = tbytes + bytes;
}