aboutsummaryrefslogtreecommitdiffstats
path: root/res/res_musiconhold.c
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-08-16 22:24:25 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-08-16 22:24:25 +0000
commit1e0bf93c56d1d0eef58ca11b67948c0a787c0665 (patch)
tree1030b346c3fb33f5c287995c6442aba90f1d90dc /res/res_musiconhold.c
parent9427c14349cb0b7ccc7531782ac551803db32469 (diff)
This patch fixes a bug where reloading the module with "module reload" did not
delete classes from memory that were no longer in the config. This patch fixes that problem as well as another one. Previously, if you reloaded MOH using the "moh reload" CLI command, which behaved differently than "module reload ...", MOH had to be stopped on every channel and started again immediately. However, there was no way to tell what class was being used, so they would all fall back to the default class. (closes issue #10139) Reported by: blitzrage Patches: asterisk-10139-advanced.diff.txt uploaded by jamesgolovich (license 176) Tested by: jamesgolovich git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@79778 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'res/res_musiconhold.c')
-rw-r--r--res/res_musiconhold.c78
1 files changed, 48 insertions, 30 deletions
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index 86b25a182..d1aa725c2 100644
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -149,6 +149,9 @@ struct mohclass {
int srcfd;
/*! FD for timing source */
int pseudofd;
+ /*! Number of users */
+ int inuse;
+ unsigned int delete:1;
AST_LIST_HEAD_NOLOCK(, mohdata) members;
AST_LIST_ENTRY(mohclass) list;
};
@@ -167,6 +170,8 @@ AST_LIST_HEAD_STATIC(mohclasses, mohclass);
#define MPG_123 "/usr/bin/mpg123"
#define MAX_MP3S 256
+static int ast_moh_destroy_one(struct mohclass *moh);
+static int reload(void);
static void ast_moh_free_class(struct mohclass **mohclass)
{
@@ -197,6 +202,8 @@ static void moh_files_release(struct ast_channel *chan, void *data)
{
struct moh_files_state *state = chan->music_state;
+ ast_atomic_fetchadd_int(&state->class->inuse, -1);
+
if (chan && state) {
if (chan->stream) {
ast_closestream(chan->stream);
@@ -210,6 +217,8 @@ static void moh_files_release(struct ast_channel *chan, void *data)
}
state->save_pos = state->pos;
}
+ if (state->class->delete && !state->class->inuse)
+ ast_moh_destroy_one(state->class);
}
@@ -685,6 +694,8 @@ static void moh_release(struct ast_channel *chan, void *data)
close(moh->pipe[0]);
close(moh->pipe[1]);
oldwfmt = moh->origwfmt;
+ if (moh->parent->delete && ast_atomic_dec_and_test(&moh->parent->inuse))
+ ast_moh_destroy_one(moh->parent);
free(moh);
if (chan) {
if (oldwfmt && ast_set_write_format(chan, oldwfmt))
@@ -844,8 +855,11 @@ static int moh_register(struct mohclass *moh, int reload)
#ifdef HAVE_ZAPTEL
int x;
#endif
+ struct mohclass *mohclass = NULL;
+
AST_LIST_LOCK(&mohclasses);
- if (get_mohbyname(moh->name, 0)) {
+ if ((mohclass = get_mohbyname(moh->name, 0))) {
+ mohclass->delete = 0;
if (reload) {
ast_log(LOG_DEBUG, "Music on Hold class '%s' left alone from initial load.\n", moh->name);
} else {
@@ -944,6 +958,8 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
mohclass = get_mohbyname(interpclass, 1);
if (!mohclass)
mohclass = get_mohbyname("default", 1);
+ if (mohclass)
+ ast_atomic_fetchadd_int(&mohclass->inuse, +1);
AST_LIST_UNLOCK(&mohclasses);
if (!mohclass)
@@ -973,7 +989,7 @@ static struct mohclass *moh_class_malloc(void)
{
struct mohclass *class;
- if ((class = ast_calloc(1, sizeof(*class))))
+ if ((class = ast_calloc(1, sizeof(*class))))
class->format = AST_FORMAT_SLINEAR;
return class;
@@ -995,6 +1011,13 @@ static int load_moh_classes(int reload)
if (!cfg)
return 0;
+ if (reload) {
+ AST_LIST_LOCK(&mohclasses);
+ AST_LIST_TRAVERSE(&mohclasses, class, list)
+ class->delete = 1;
+ AST_LIST_UNLOCK(&mohclasses);
+ }
+
cat = ast_category_browse(cfg, NULL);
for (; cat; cat = ast_category_browse(cfg, cat)) {
if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) {
@@ -1111,17 +1134,12 @@ static int load_moh_classes(int reload)
return numclasses;
}
-static void ast_moh_destroy(void)
+static int ast_moh_destroy_one(struct mohclass *moh)
{
- struct mohclass *moh;
char buff[8192];
int bytes, tbytes = 0, stime = 0, pid = 0;
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
-
- AST_LIST_LOCK(&mohclasses);
- while ((moh = AST_LIST_REMOVE_HEAD(&mohclasses, list))) {
+ if (moh) {
if (moh->pid > 1) {
ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
stime = time(NULL) + 2;
@@ -1142,33 +1160,27 @@ static void ast_moh_destroy(void)
}
ast_moh_free_class(&moh);
}
- AST_LIST_UNLOCK(&mohclasses);
+
+ return 0;
}
-static void moh_on_off(int on)
+static void ast_moh_destroy(void)
{
- struct ast_channel *chan = NULL;
-
- while ( (chan = ast_channel_walk_locked(chan)) != NULL) {
- if (ast_test_flag(chan, AST_FLAG_MOH)) {
- if (on)
- local_ast_moh_start(chan, NULL, NULL);
- else
- ast_deactivate_generator(chan);
- }
- ast_channel_unlock(chan);
+ struct mohclass *moh;
+
+ if (option_verbose > 1)
+ ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
+
+ AST_LIST_LOCK(&mohclasses);
+ while ((moh = AST_LIST_REMOVE_HEAD(&mohclasses, list))) {
+ ast_moh_destroy_one(moh);
}
+ AST_LIST_UNLOCK(&mohclasses);
}
static int moh_cli(int fd, int argc, char *argv[])
{
- int x;
-
- moh_on_off(0);
- ast_moh_destroy();
- x = load_moh_classes(1);
- moh_on_off(1);
- ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es");
+ reload();
return 0;
}
@@ -1200,6 +1212,7 @@ static int moh_classes_show(int fd, int argc, char *argv[])
ast_cli(fd, "Class: %s\n", class->name);
ast_cli(fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
+ ast_cli(fd, "\tUse Count: %d\n", class->inuse);
if (ast_test_flag(class, MOH_CUSTOM))
ast_cli(fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
if (strcasecmp(class->mode, "files"))
@@ -1242,10 +1255,15 @@ static int init_classes(int reload)
return 0; /* Return if nothing is found */
AST_LIST_LOCK(&mohclasses);
- AST_LIST_TRAVERSE(&mohclasses, moh, list) {
- if (moh->total_files)
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&mohclasses, moh, list) {
+ if (reload && moh->delete) {
+ AST_LIST_REMOVE_CURRENT(&mohclasses, list);
+ if (!moh->inuse)
+ ast_moh_destroy_one(moh);
+ } else if (moh->total_files)
moh_scan_files(moh);
}
+ AST_LIST_TRAVERSE_SAFE_END
AST_LIST_UNLOCK(&mohclasses);
return 1;