aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-02-21 00:19:14 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-02-21 00:19:14 +0000
commit5c161c3a8f48efea543766c756692854949d832c (patch)
tree49775a9a6ea0364f47b975ed791f8081d349e79a
parent1d1a115108d8ae01a7b4f843b2631e479bb52fca (diff)
Fix random crashes when using the MeetMe application. This patch converts list
handling to use the linked list macros and most importantly, implements reference counting on the ast_conference objects. The reference counting was first backported from 1.4. However, that code has some problems that caused the reference count to never hit zero. Those problems are fixed in this patch and will be resolved in 1.4 and trunk next, with a different patch. (issues #7647, #9073, #9106, BE-115). git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.2@55750 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--apps/app_meetme.c322
-rw-r--r--include/asterisk/lock.h27
-rw-r--r--utils.c11
3 files changed, 173 insertions, 187 deletions
diff --git a/apps/app_meetme.c b/apps/app_meetme.c
index 1efd4bbb4..1b9b12952 100644
--- a/apps/app_meetme.c
+++ b/apps/app_meetme.c
@@ -54,6 +54,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/cli.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
+#include "asterisk/linkedlists.h"
static const char *tdesc = "MeetMe conference bridge";
@@ -129,16 +130,16 @@ STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
-static struct ast_conference {
+struct ast_conference {
char confno[AST_MAX_EXTENSION]; /* Conference */
struct ast_channel *chan; /* Announcements channel */
int fd; /* Announcements fd */
int zapconf; /* Zaptel Conf # */
int users; /* Number of active users */
int markedusers; /* Number of marked users */
- struct ast_conf_user *firstuser; /* Pointer to the first user struct */
- struct ast_conf_user *lastuser; /* Pointer to the last user struct */
+ AST_LIST_HEAD_NOLOCK(, ast_conf_user) userlist;
time_t start; /* Start time (s) */
+ int refcount;
int recording; /* recording status */
int isdynamic; /* Created on the fly? */
int locked; /* Is the conference locked? */
@@ -148,8 +149,10 @@ static struct ast_conference {
char *recordingformat; /* Format to record the Conference in */
char pin[AST_MAX_EXTENSION]; /* If protected by a PIN */
char pinadmin[AST_MAX_EXTENSION]; /* If protected by a admin PIN */
- struct ast_conference *next;
-} *confs;
+ AST_LIST_ENTRY(ast_conference) list;
+};
+
+static AST_LIST_HEAD_STATIC(confs, ast_conference);
struct volume {
int desired; /* Desired volume adjustment */
@@ -158,8 +161,7 @@ struct volume {
struct ast_conf_user {
int user_no; /* User Number */
- struct ast_conf_user *prevuser; /* Pointer to the previous user */
- struct ast_conf_user *nextuser; /* Pointer to the next user */
+ AST_LIST_ENTRY(ast_conf_user) list;
int userflags; /* Flags as set in the conference */
int adminflags; /* Flags set by the Admin */
struct ast_channel *chan; /* Connected channel */
@@ -188,8 +190,6 @@ enum volume_action {
VOL_DOWN,
};
-AST_MUTEX_DEFINE_STATIC(conflock);
-
static int admin_exec(struct ast_channel *chan, void *data);
static void *recordthread(void *args);
@@ -414,7 +414,7 @@ static void conf_play(struct ast_channel *chan, struct ast_conference *conf, int
if (!chan->_softhangup)
res = ast_autoservice_start(chan);
- ast_mutex_lock(&conflock);
+ AST_LIST_LOCK(&confs);
switch(sound) {
case ENTER:
@@ -432,20 +432,19 @@ static void conf_play(struct ast_channel *chan, struct ast_conference *conf, int
if (data)
careful_write(conf->fd, data, len, 1);
- ast_mutex_unlock(&conflock);
+ AST_LIST_UNLOCK(&confs);
if (!res)
ast_autoservice_stop(chan);
}
-static struct ast_conference *build_conf(char *confno, char *pin, char *pinadmin, int make, int dynamic)
+static struct ast_conference *build_conf(char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount)
{
struct ast_conference *cnf;
struct zt_confinfo ztc;
- ast_mutex_lock(&conflock);
-
- for (cnf = confs; cnf; cnf = cnf->next) {
+ AST_LIST_LOCK(&confs);
+ AST_LIST_TRAVERSE(&confs, cnf, list) {
if (!strcmp(confno, cnf->confno))
break;
}
@@ -490,18 +489,17 @@ static struct ast_conference *build_conf(char *confno, char *pin, char *pinadmin
cnf->start = time(NULL);
cnf->zapconf = ztc.confno;
cnf->isdynamic = dynamic;
- cnf->firstuser = NULL;
- cnf->lastuser = NULL;
cnf->locked = 0;
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Created MeetMe conference %d for conference '%s'\n", cnf->zapconf, cnf->confno);
- cnf->next = confs;
- confs = cnf;
+ AST_LIST_INSERT_HEAD(&confs, cnf, list);
} else
ast_log(LOG_WARNING, "Out of memory\n");
}
cnfout:
- ast_mutex_unlock(&conflock);
+ if (cnf)
+ ast_atomic_fetchadd_int(&cnf->refcount, refcount);
+ AST_LIST_UNLOCK(&confs);
return cnf;
}
@@ -540,13 +538,14 @@ static int conf_cmd(int fd, int argc, char **argv) {
if (argc == 1) {
/* 'MeetMe': List all the conferences */
now = time(NULL);
- cnf = confs;
- if (!cnf) {
+ AST_LIST_LOCK(&confs);
+ if (!AST_LIST_FIRST(&confs)) {
ast_cli(fd, "No active MeetMe conferences.\n");
+ AST_LIST_UNLOCK(&confs);
return RESULT_SUCCESS;
}
ast_cli(fd, header_format, "Conf Num", "Parties", "Marked", "Activity", "Creation");
- while(cnf) {
+ AST_LIST_TRAVERSE(&confs, cnf, list) {
if (cnf->markedusers == 0)
strcpy(cmdline, "N/A ");
else
@@ -558,9 +557,9 @@ static int conf_cmd(int fd, int argc, char **argv) {
ast_cli(fd, data_format, cnf->confno, cnf->users, cmdline, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static");
total += cnf->users;
- cnf = cnf->next;
}
ast_cli(fd, "* Total number of MeetMe users: %d\n", total);
+ AST_LIST_UNLOCK(&confs);
return RESULT_SUCCESS;
}
if (argc < 3)
@@ -607,24 +606,22 @@ static int conf_cmd(int fd, int argc, char **argv) {
}
} else if(strcmp(argv[1], "list") == 0) {
/* List all the users in a conference */
- if (!confs) {
+ if (!AST_LIST_FIRST(&confs)) {
ast_cli(fd, "No active conferences.\n");
return RESULT_SUCCESS;
}
- cnf = confs;
- /* Find the right conference */
- while(cnf) {
+ AST_LIST_LOCK(&confs);
+ AST_LIST_TRAVERSE(&confs, cnf, list) {
if (strcmp(cnf->confno, argv[2]) == 0)
break;
- if (cnf->next) {
- cnf = cnf->next;
- } else {
- ast_cli(fd, "No such conference: %s.\n",argv[2]);
- return RESULT_SUCCESS;
- }
+ }
+ if (!cnf) {
+ ast_cli(fd, "No such conference: %s.\n", argv[2]);
+ AST_LIST_UNLOCK(&confs);
+ return RESULT_SUCCESS;
}
/* Show all the users */
- for (user = cnf->firstuser; user; user = user->nextuser)
+ AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
ast_cli(fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s\n",
user->user_no,
user->chan->cid.cid_num ? user->chan->cid.cid_num : "<unknown>",
@@ -634,7 +631,9 @@ static int conf_cmd(int fd, int argc, char **argv) {
user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : "",
istalking(user->talking));
+ }
ast_cli(fd,"%d users in that conference.\n",cnf->users);
+ AST_LIST_UNLOCK(&confs);
return RESULT_SUCCESS;
} else
@@ -654,6 +653,7 @@ static char *complete_confcmd(char *line, char *word, int pos, int state) {
char usrno[50] = "";
char cmds[CONF_COMMANDS][20] = {"lock", "unlock", "mute", "unmute", "kick", "list"};
char *myline;
+ char *res = NULL;
if (pos == 1) {
/* Command */
@@ -666,17 +666,16 @@ static char *complete_confcmd(char *line, char *word, int pos, int state) {
}
} else if (pos == 2) {
/* Conference Number */
- ast_mutex_lock(&conflock);
- cnf = confs;
- while(cnf) {
+ AST_LIST_LOCK(&confs);
+ AST_LIST_TRAVERSE(&confs, cnf, list) {
if (!strncasecmp(word, cnf->confno, strlen(word))) {
if (++which > state)
break;
}
- cnf = cnf->next;
}
- ast_mutex_unlock(&conflock);
- return cnf ? strdup(cnf->confno) : NULL;
+ res = cnf ? strdup(cnf->confno) : NULL;
+ AST_LIST_UNLOCK(&confs);
+ return res;
} else if (pos == 3) {
/* User Number || Conf Command option*/
if (strstr(line, "mute") || strstr(line, "kick")) {
@@ -684,7 +683,7 @@ static char *complete_confcmd(char *line, char *word, int pos, int state) {
return strdup("all");
}
which++;
- ast_mutex_lock(&conflock);
+ AST_LIST_LOCK(&confs);
/* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
myline = ast_strdupa(line);
@@ -692,15 +691,15 @@ static char *complete_confcmd(char *line, char *word, int pos, int state) {
while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
;
}
-
- for (cnf = confs; cnf; cnf = cnf->next) {
+
+ AST_LIST_TRAVERSE(&confs, cnf, list) {
if (!strcmp(confno, cnf->confno))
break;
}
if (cnf) {
/* Search for the user */
- for (usr = cnf->firstuser; usr; usr = usr->nextuser) {
+ AST_LIST_TRAVERSE(&cnf->userlist, usr, list) {
snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
if (!strncasecmp(word, usrno, strlen(word))) {
if (++which > state)
@@ -708,7 +707,7 @@ static char *complete_confcmd(char *line, char *word, int pos, int state) {
}
}
}
- ast_mutex_unlock(&conflock);
+ AST_LIST_UNLOCK(&confs);
return usr ? strdup(usrno) : NULL;
}
}
@@ -754,34 +753,31 @@ static void conf_flush(int fd, struct ast_channel *chan)
}
/* Remove the conference from the list and free it.
- We assume that this was called while holding conflock. */
+ XXX We assume that this was called while holding the confs list lock. */
static int conf_free(struct ast_conference *conf)
{
- struct ast_conference *prev = NULL, *cur = confs;
+ struct ast_conference *cur;
- while (cur) {
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&confs, cur, list) {
if (cur == conf) {
- if (prev)
- prev->next = conf->next;
- else
- confs = conf->next;
+ AST_LIST_REMOVE_CURRENT(&confs, list);
break;
}
- prev = cur;
- cur = cur->next;
}
+ AST_LIST_TRAVERSE_SAFE_END;
if (!cur)
ast_log(LOG_WARNING, "Conference not found\n");
if (conf->recording == MEETME_RECORD_ACTIVE) {
conf->recording = MEETME_RECORD_TERMINATE;
- ast_mutex_unlock(&conflock);
+ AST_LIST_UNLOCK(&confs);
while (1) {
- ast_mutex_lock(&conflock);
+ usleep(1);
+ AST_LIST_LOCK(&confs);
if (conf->recording == MEETME_RECORD_OFF)
break;
- ast_mutex_unlock(&conflock);
+ AST_LIST_UNLOCK(&confs);
}
}
@@ -795,6 +791,21 @@ static int conf_free(struct ast_conference *conf)
return 0;
}
+/* Decrement reference counts, as incremented by find_conf() */
+static int dispose_conf(struct ast_conference *conf)
+{
+ int res = 0;
+
+ AST_LIST_LOCK(&confs);
+ if (ast_atomic_dec_and_test(&conf->refcount)) {
+ conf_free(conf);
+ res = 1;
+ }
+ AST_LIST_UNLOCK(&confs);
+
+ return res;
+}
+
static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags, char *optargs[])
{
struct ast_conf_user *user = calloc(1, sizeof(*user));
@@ -846,6 +857,8 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
timeout = time(NULL) + opt_waitmarked_timeout;
}
+ AST_LIST_LOCK(&confs);
+
if (confflags & CONFFLAG_RECORDCONF && conf->recording !=MEETME_RECORD_ACTIVE) {
conf->recordingfilename = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE");
if (!conf->recordingfilename) {
@@ -871,38 +884,28 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
/* Sorry, but this confernce is locked! */
if (!ast_streamfile(chan, "conf-locked", chan->language))
ast_waitstream(chan, "");
+ AST_LIST_UNLOCK(&confs);
goto outrun;
}
if (confflags & CONFFLAG_MARKEDUSER)
conf->markedusers++;
-
- ast_mutex_lock(&conflock);
- if (!conf->firstuser) {
- /* Fill the first new User struct */
+
+ if (AST_LIST_LAST(&conf->userlist))
+ user->user_no = AST_LIST_LAST(&conf->userlist)->user_no + 1;
+ else
user->user_no = 1;
- conf->firstuser = user;
- conf->lastuser = user;
- } else {
- /* Fill the new user struct */
- user->user_no = conf->lastuser->user_no + 1;
- user->prevuser = conf->lastuser;
- if (conf->lastuser->nextuser) {
- ast_log(LOG_WARNING, "Error in User Management!\n");
- ast_mutex_unlock(&conflock);
- goto outrun;
- } else {
- conf->lastuser->nextuser = user;
- conf->lastuser = user;
- }
- }
user->chan = chan;
user->userflags = confflags;
user->adminflags = 0;
user->talking = -1;
conf->users++;
- ast_mutex_unlock(&conflock);
+
+ AST_LIST_INSERT_TAIL(&conf->userlist, user, list);
+
+ /* Since we control a user in the userlist, our conference should never go away now. */
+ AST_LIST_UNLOCK(&confs);
if (confflags & CONFFLAG_EXIT_CONTEXT) {
if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT")))
@@ -1051,7 +1054,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
ztc.chan = 0;
ztc.confno = conf->zapconf;
- ast_mutex_lock(&conflock);
+ AST_LIST_LOCK(&confs);
if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_INTROUSER) && conf->users > 1) {
if (conf->chan && ast_fileexists(user->namerecloc, NULL, NULL)) {
@@ -1072,7 +1075,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
if (ioctl(fd, ZT_SETCONF, &ztc)) {
ast_log(LOG_WARNING, "Error setting conference\n");
close(fd);
- ast_mutex_unlock(&conflock);
+ AST_LIST_UNLOCK(&confs);
goto outrun;
}
ast_log(LOG_DEBUG, "Placed channel %s in ZAP conf %d\n", chan->name, conf->zapconf);
@@ -1091,7 +1094,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
conf_play(chan, conf, ENTER);
}
- ast_mutex_unlock(&conflock);
+ AST_LIST_UNLOCK(&confs);
conf_flush(fd, chan);
@@ -1425,7 +1428,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
break;
case '3': /* Eject last user */
menu_active = 0;
- usr = conf->lastuser;
+ usr = AST_LIST_LAST(&conf->userlist);
if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
if(!ast_streamfile(chan, "conf-errormenu", chan->language))
ast_waitstream(chan, "");
@@ -1570,7 +1573,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
reset_volumes(user);
- ast_mutex_lock(&conflock);
+ AST_LIST_LOCK(&confs);
if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
conf_play(chan, conf, LEAVE);
@@ -1585,14 +1588,14 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
ast_filedelete(user->namerecloc, NULL);
}
}
- ast_mutex_unlock(&conflock);
+ AST_LIST_UNLOCK(&confs);
outrun:
- ast_mutex_lock(&conflock);
+ AST_LIST_LOCK(&confs);
if (confflags & CONFFLAG_MONITORTALKER && dsp)
ast_dsp_free(dsp);
-
+
if (user->user_no) { /* Only cleanup users who really joined! */
manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
"Channel: %s\r\n"
@@ -1603,62 +1606,33 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
conf->users--;
if (confflags & CONFFLAG_MARKEDUSER)
conf->markedusers--;
- if (!conf->users) {
- /* No more users -- close this one out */
- conf_free(conf);
- } else {
- /* Remove the user struct */
- if (user == conf->firstuser) {
- if (user->nextuser) {
- /* There is another entry */
- user->nextuser->prevuser = NULL;
- } else {
- /* We are the only entry */
- conf->lastuser = NULL;
- }
- /* In either case */
- conf->firstuser = user->nextuser;
- } else if (user == conf->lastuser){
- if (user->prevuser)
- user->prevuser->nextuser = NULL;
- else
- ast_log(LOG_ERROR, "Bad bad bad! We're the last, not the first, but nobody before us??\n");
- conf->lastuser = user->prevuser;
- } else {
- if (user->nextuser)
- user->nextuser->prevuser = user->prevuser;
- else
- ast_log(LOG_ERROR, "Bad! Bad! Bad! user->nextuser is NULL but we're not the end!\n");
- if (user->prevuser)
- user->prevuser->nextuser = user->nextuser;
- else
- ast_log(LOG_ERROR, "Bad! Bad! Bad! user->prevuser is NULL but we're not the beginning!\n");
- }
- }
+ AST_LIST_REMOVE(&conf->userlist, user, list);
/* Return the number of seconds the user was in the conf */
snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
}
free(user);
- ast_mutex_unlock(&conflock);
+ AST_LIST_UNLOCK(&confs);
return ret;
}
static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin,
- struct ast_flags *confflags)
+ int refcount, struct ast_flags *confflags)
{
struct ast_config *cfg;
struct ast_variable *var;
struct ast_conference *cnf;
/* Check first in the conference list */
- ast_mutex_lock(&conflock);
- for (cnf = confs; cnf; cnf = cnf->next) {
+ AST_LIST_LOCK(&confs);
+ AST_LIST_TRAVERSE(&confs, cnf, list) {
if (!strcmp(confno, cnf->confno))
break;
}
- ast_mutex_unlock(&conflock);
+ if (cnf)
+ ast_atomic_fetchadd_int(&cnf->refcount, refcount);
+ AST_LIST_UNLOCK(&confs);
if (!cnf) {
if (dynamic) {
@@ -1670,9 +1644,9 @@ static struct ast_conference *find_conf(struct ast_channel *chan, char *confno,
if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, AST_MAX_EXTENSION - 1, 0) < 0)
return NULL;
}
- cnf = build_conf(confno, dynamic_pin, "", make, dynamic);
+ cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount);
} else {
- cnf = build_conf(confno, "", "", make, dynamic);
+ cnf = build_conf(confno, "", "", make, dynamic, refcount);
}
} else {
/* Check the config */
@@ -1694,14 +1668,14 @@ static struct ast_conference *find_conf(struct ast_channel *chan, char *confno,
/* Bingo it's a valid conference */
if (pin)
if (pinadmin)
- cnf = build_conf(confno, pin, pinadmin, make, dynamic);
+ cnf = build_conf(confno, pin, pinadmin, make, dynamic, refcount);
else
- cnf = build_conf(confno, pin, "", make, dynamic);
+ cnf = build_conf(confno, pin, "", make, dynamic, refcount);
else
if (pinadmin)
- cnf = build_conf(confno, "", pinadmin, make, dynamic);
+ cnf = build_conf(confno, "", pinadmin, make, dynamic, refcount);
else
- cnf = build_conf(confno, "", "", make, dynamic);
+ cnf = build_conf(confno, "", "", make, dynamic, refcount);
break;
}
}
@@ -1764,10 +1738,12 @@ static int count_exec(struct ast_channel *chan, void *data)
}
confnum = strsep(&localdata,"|");
- conf = find_conf(chan, confnum, 0, 0, NULL, NULL);
- if (conf)
+ conf = find_conf(chan, confnum, 0, 0, NULL, 1, NULL);
+ if (conf) {
count = conf->users;
- else
+ dispose_conf(conf);
+ conf = NULL;
+ } else
count = 0;
if (!ast_strlen_zero(localdata)){
@@ -1792,7 +1768,7 @@ static int conf_exec(struct ast_channel *chan, void *data)
char confno[AST_MAX_EXTENSION] = "";
int allowretry = 0;
int retrycnt = 0;
- struct ast_conference *cnf;
+ struct ast_conference *cnf = NULL;
struct ast_flags confflags = {0};
int dynamic = 0;
int empty = 0, empty_no_pin = 0;
@@ -1848,15 +1824,15 @@ static int conf_exec(struct ast_channel *chan, void *data)
struct ast_variable *var;
int confno_int;
- ast_mutex_lock(&conflock);
- for (cnf = confs; cnf; cnf = cnf->next) {
+ AST_LIST_LOCK(&confs);
+ AST_LIST_TRAVERSE(&confs, cnf, list) {
if (sscanf(cnf->confno, "%d", &confno_int) == 1) {
/* Disqualify in use conference */
if (confno_int >= 0 && confno_int < 1024)
map[confno_int]++;
}
}
- ast_mutex_unlock(&conflock);
+ AST_LIST_UNLOCK(&confs);
/* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
if ((empty_no_pin) || (!dynamic)) {
@@ -1878,17 +1854,15 @@ static int conf_exec(struct ast_channel *chan, void *data)
}
if (!dynamic) {
/* For static: run through the list and see if this conference is empty */
- ast_mutex_lock(&conflock);
- cnf = confs;
- while (cnf) {
+ AST_LIST_LOCK(&confs);
+ AST_LIST_TRAVERSE(&confs, cnf, list) {
if (!strcmp(confno_tmp, cnf->confno)) {
/* The conference exists, therefore it's not empty */
found = 1;
break;
}
- cnf = cnf->next;
}
- ast_mutex_unlock(&conflock);
+ AST_LIST_UNLOCK(&confs);
if (!found) {
/* At this point, we have a confno_tmp (static conference) that is empty */
if ((empty_no_pin && ((!stringp) || (stringp && (stringp[0] == '\0')))) || (!empty_no_pin)) {
@@ -1952,7 +1926,7 @@ static int conf_exec(struct ast_channel *chan, void *data)
}
if (!ast_strlen_zero(confno)) {
/* Check the validity of the conference */
- cnf = find_conf(chan, confno, 1, dynamic, the_pin, &confflags);
+ cnf = find_conf(chan, confno, 1, dynamic, the_pin, 1, &confflags);
if (!cnf) {
res = ast_streamfile(chan, "conf-invalid", chan->language);
if (!res)
@@ -2010,19 +1984,12 @@ static int conf_exec(struct ast_channel *chan, void *data)
/* failed when getting the pin */
res = -1;
allowretry = 0;
- /* see if we need to get rid of the conference */
- ast_mutex_lock(&conflock);
- if (!cnf->users) {
- conf_free(cnf);
- }
- ast_mutex_unlock(&conflock);
break;
}
/* Don't retry pin with a static pin */
- if (*the_pin && (always_prompt==0)) {
+ if (*the_pin && !always_prompt)
break;
- }
}
} else {
/* No pin required */
@@ -2031,10 +1998,15 @@ static int conf_exec(struct ast_channel *chan, void *data)
/* Run the conference */
res = conf_run(chan, cnf, confflags.flags, optargs);
}
+ dispose_conf(cnf);
+ cnf = NULL;
}
}
} while (allowretry);
-
+
+ if (cnf)
+ dispose_conf(cnf);
+
LOCAL_USER_REMOVE(u);
return res;
@@ -2051,11 +2023,9 @@ static struct ast_conf_user* find_user(struct ast_conference *conf, char *caller
sscanf(callerident, "%i", &cid);
- user = conf->firstuser;
- while (user) {
+ AST_LIST_TRAVERSE(&conf->userlist, user, list) {
if (user->user_no == cid)
break;
- user = user->nextuser;
}
return user;
@@ -2071,9 +2041,8 @@ static int admin_exec(struct ast_channel *chan, void *data) {
LOCAL_USER_ADD(u);
- ast_mutex_lock(&conflock);
/* The param has the conference number the user and the command to execute */
- if (!ast_strlen_zero(data)) {
+ if (!ast_strlen_zero(data)) {
params = ast_strdupa((char *) data);
conf = strsep(&params, "|");
command = strsep(&params, "|");
@@ -2081,15 +2050,12 @@ static int admin_exec(struct ast_channel *chan, void *data) {
if (!command) {
ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
- ast_mutex_unlock(&conflock);
LOCAL_USER_REMOVE(u);
return -1;
}
- for (cnf = confs; cnf; cnf = cnf->next) {
- if (!strcmp(cnf->confno, conf))
- break;
- }
-
+
+ cnf = find_conf(chan, conf, 0, 0, NULL, 1, NULL);
+
if (caller)
user = find_user(cnf, caller);
@@ -2102,18 +2068,12 @@ static int admin_exec(struct ast_channel *chan, void *data) {
cnf->locked = 0;
break;
case 75: /* K: kick all users*/
- user = cnf->firstuser;
- while(user) {
+ AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
user->adminflags |= ADMINFLAG_KICKME;
- if (user->nextuser) {
- user = user->nextuser;
- } else {
- break;
- }
}
break;
case 101: /* e: Eject last user*/
- user = cnf->lastuser;
+ user = AST_LIST_LAST(&cnf->userlist);
if (!(user->userflags & CONFFLAG_ADMIN)) {
user->adminflags |= ADMINFLAG_KICKME;
break;
@@ -2128,15 +2088,9 @@ static int admin_exec(struct ast_channel *chan, void *data) {
}
break;
case 78: /* N: Mute all users */
- user = cnf->firstuser;
- while(user) {
+ AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
if (user && !(user->userflags & CONFFLAG_ADMIN))
user->adminflags |= ADMINFLAG_MUTED;
- if (user->nextuser) {
- user = user->nextuser;
- } else {
- break;
- }
}
break;
case 109: /* m: Unmute */
@@ -2147,16 +2101,10 @@ static int admin_exec(struct ast_channel *chan, void *data) {
}
break;
case 110: /* n: Unmute all users */
- user = cnf->firstuser;
- while(user) {
+ AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
if (user && (user-> adminflags & ADMINFLAG_MUTED)) {
user->adminflags ^= ADMINFLAG_MUTED;
}
- if (user->nextuser) {
- user = user->nextuser;
- } else {
- break;
- }
}
break;
case 107: /* k: Kick user */
@@ -2167,11 +2115,13 @@ static int admin_exec(struct ast_channel *chan, void *data) {
}
break;
}
+
+ dispose_conf(cnf);
+ cnf = NULL;
} else {
ast_log(LOG_NOTICE, "Conference Number not found\n");
}
}
- ast_mutex_unlock(&conflock);
LOCAL_USER_REMOVE(u);
@@ -2210,8 +2160,6 @@ static void *recordthread(void *args)
}
ast_frfree(f);
if (cnf->recording == MEETME_RECORD_TERMINATE) {
- ast_mutex_lock(&conflock);
- ast_mutex_unlock(&conflock);
break;
}
}
diff --git a/include/asterisk/lock.h b/include/asterisk/lock.h
index dc9cf9a28..67deba4dd 100644
--- a/include/asterisk/lock.h
+++ b/include/asterisk/lock.h
@@ -666,4 +666,31 @@ static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const str
#define pthread_create __use_ast_pthread_create_instead__
#endif
+int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
+
+#include "asterisk/inline_api.h"
+
+#if defined (__i386__)
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
+{
+ __asm __volatile (
+ " lock xaddl %0, %1 ; "
+ : "+r" (v), /* 0 (result) */
+ "=m" (*p) /* 1 */
+ : "m" (*p)); /* 2 */
+ return (v);
+})
+#else /* low performance version in utils.c */
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
+{
+ return ast_atomic_fetchadd_int_slow(p, v);
+})
+#endif
+
+AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
+{
+ int a = ast_atomic_fetchadd_int(p, -1);
+ return a == 1; /* true if the value is 0 now (so it was 1 previously) */
+})
+
#endif /* _ASTERISK_LOCK_H */
diff --git a/utils.c b/utils.c
index 6b3680b8f..321f9113a 100644
--- a/utils.c
+++ b/utils.c
@@ -907,3 +907,14 @@ void ast_enable_packet_fragmentation(int sock)
#endif
}
+AST_MUTEX_DEFINE_STATIC(fetchadd_m); /* used for all fetc&add ops */
+
+int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
+{
+ int ret;
+ ast_mutex_lock(&fetchadd_m);
+ ret = *p;
+ *p += v;
+ ast_mutex_unlock(&fetchadd_m);
+ return ret;
+}