Index: res/res_musiconhold.c =================================================================== --- res/res_musiconhold.c (revision 79637) +++ res/res_musiconhold.c (working copy) @@ -149,6 +149,9 @@ int srcfd; /*! FD for timing source */ int pseudofd; + /*! Number of users */ + int inuse; + int delete; AST_LIST_HEAD_NOLOCK(, mohdata) members; AST_LIST_ENTRY(mohclass) list; }; @@ -167,6 +170,8 @@ #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,10 @@ { struct moh_files_state *state = chan->music_state; + AST_RWLIST_WRLOCK(&mohclasses); + state->class->inuse--; + AST_RWLIST_UNLOCK(&mohclasses); + if (chan && state) { if (chan->stream) { ast_closestream(chan->stream); @@ -209,6 +218,8 @@ } state->save_pos = state->pos; } + if (state->class->delete && !state->class->inuse) + ast_moh_destroy_one(state->class); } @@ -707,12 +718,15 @@ int oldwfmt; AST_RWLIST_WRLOCK(&mohclasses); + moh->parent->inuse--; AST_RWLIST_REMOVE(&moh->parent->members, moh, list); AST_RWLIST_UNLOCK(&mohclasses); close(moh->pipe[0]); close(moh->pipe[1]); oldwfmt = moh->origwfmt; + if (moh->parent->delete && !moh->parent->inuse) + ast_moh_destroy_one(moh->parent); ast_free(moh); if (chan) { if (oldwfmt && ast_set_write_format(chan, oldwfmt)) @@ -871,8 +885,11 @@ #ifdef HAVE_ZAPTEL int x; #endif + struct mohclass *mohclass = NULL; + AST_RWLIST_WRLOCK(&mohclasses); - if (get_mohbyname(moh->name, 0)) { + if ((mohclass = get_mohbyname(moh->name, 0))) { + mohclass->delete = 0; if (reload) { ast_debug(1, "Music on Hold class '%s' left alone from initial load.\n", moh->name); } else { @@ -971,6 +988,8 @@ mohclass = get_mohbyname(interpclass, 1); if (!mohclass) mohclass = get_mohbyname("default", 1); + if (mohclass) + mohclass->inuse++; AST_RWLIST_UNLOCK(&mohclasses); if (!mohclass) @@ -1000,8 +1019,11 @@ { struct mohclass *class; - if ((class = ast_calloc(1, sizeof(*class)))) + if ((class = ast_calloc(1, sizeof(*class)))) { class->format = AST_FORMAT_SLINEAR; + class->inuse = 0; + class->delete = 0; + } return class; } @@ -1019,6 +1041,14 @@ if (!cfg) return 0; + if (reload) { + AST_RWLIST_WRLOCK(&mohclasses); + AST_RWLIST_TRAVERSE(&mohclasses, class, list) { + class->delete = 1; + } + AST_RWLIST_UNLOCK(&mohclasses); + } + cat = ast_category_browse(cfg, NULL); for (; cat; cat = ast_category_browse(cfg, cat)) { /* These names were deprecated in 1.4 and should not be used until after the next major release. */ @@ -1081,16 +1111,12 @@ 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; - ast_verb(2, "Destroying musiconhold processes\n"); - - AST_RWLIST_WRLOCK(&mohclasses); - while ((moh = AST_RWLIST_REMOVE_HEAD(&mohclasses, list))) { + if (moh) { if (moh->pid > 1) { ast_debug(1, "killing %d!\n", moh->pid); stime = time(NULL) + 2; @@ -1111,33 +1137,27 @@ } ast_moh_free_class(&moh); } - AST_RWLIST_UNLOCK(&mohclasses); + + return 0; } -static void moh_on_off(int on) +static void ast_moh_destroy(void) { - struct ast_channel *chan = NULL; + struct mohclass *moh; - 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); + ast_verb(2, "Destroying musiconhold processes\n"); + + AST_RWLIST_WRLOCK(&mohclasses); + while ((moh = AST_RWLIST_REMOVE_HEAD(&mohclasses, list))) { + ast_moh_destroy_one(moh); } + AST_RWLIST_UNLOCK(&mohclasses); } static int moh_cli(int fd, int argc, char *argv[]) { - int x; + reload(); - 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"); return 0; } @@ -1169,6 +1189,7 @@ ast_cli(fd, "Class: %s\n", class->name); ast_cli(fd, "\tMode: %s\n", S_OR(class->mode, "")); ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "")); + ast_cli(fd, "\tInUse: %d\n", class->inuse); if (class->digit) ast_cli(fd, "\tDigit: %c\n", class->digit); if (ast_test_flag(class, MOH_CUSTOM)) @@ -1203,10 +1224,15 @@ return 0; /* Return if nothing is found */ AST_RWLIST_WRLOCK(&mohclasses); - AST_RWLIST_TRAVERSE(&mohclasses, moh, list) { - if (moh->total_files) + AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mohclasses, moh, list) { + if (reload && moh->delete) { + AST_RWLIST_REMOVE_CURRENT(&mohclasses, list); + if (!moh->inuse) + ast_moh_destroy_one(moh); + } else if (moh->total_files) moh_scan_files(moh); } + AST_RWLIST_TRAVERSE_SAFE_END AST_RWLIST_UNLOCK(&mohclasses); return 1;