[asterisk-commits] russell: branch 1.2 r55750 - in /branches/1.2: ./ apps/ include/asterisk/

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Tue Feb 20 17:19:15 MST 2007


Author: russell
Date: Tue Feb 20 18:19:14 2007
New Revision: 55750

URL: http://svn.digium.com/view/asterisk?view=rev&rev=55750
Log:
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). 

Modified:
    branches/1.2/apps/app_meetme.c
    branches/1.2/include/asterisk/lock.h
    branches/1.2/utils.c

Modified: branches/1.2/apps/app_meetme.c
URL: http://svn.digium.com/view/asterisk/branches/1.2/apps/app_meetme.c?view=diff&rev=55750&r1=55749&r2=55750
==============================================================================
--- branches/1.2/apps/app_meetme.c (original)
+++ branches/1.2/apps/app_meetme.c Tue Feb 20 18:19:14 2007
@@ -54,6 +54,7 @@
 #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 @@
 
 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 @@
 	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 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 */
@@ -187,8 +189,6 @@
 	VOL_UP,
 	VOL_DOWN,
 };
-
-AST_MUTEX_DEFINE_STATIC(conflock);
 
 static int admin_exec(struct ast_channel *chan, void *data);
 
@@ -414,7 +414,7 @@
 	if (!chan->_softhangup)
 		res = ast_autoservice_start(chan);
 
-	ast_mutex_lock(&conflock);
+	AST_LIST_LOCK(&confs);
 
 	switch(sound) {
 	case ENTER:
@@ -432,20 +432,19 @@
 	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 @@
 			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 @@
 	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 @@
 			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 @@
 		}	
 	} 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 @@
 				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 @@
 	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 @@
 		}
 	} 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 @@
 				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 @@
 				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 @@
 					}
 				}
 			}
-			ast_mutex_unlock(&conflock);
+			AST_LIST_UNLOCK(&confs);
 			return usr ? strdup(usrno) : NULL;
 		}
 	}
@@ -754,34 +753,31 @@
 }
 
 /* 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;
-
-	while (cur) {
+	struct ast_conference *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);
 		}
 	}
 
@@ -793,6 +789,21 @@
 	free(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[])
@@ -846,6 +857,8 @@
 		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 @@
 		/* 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 @@
 	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 @@
 	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 @@
 				conf_play(chan, conf, ENTER);
 	}
 
-	ast_mutex_unlock(&conflock);
+	AST_LIST_UNLOCK(&confs);
 
 	conf_flush(fd, chan);
 
@@ -1425,7 +1428,7 @@
 								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 @@
 
 	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 @@
 			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 @@
 		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 @@
 					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 @@
 							/* 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 @@
 	}
 	
 	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 @@
 	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 @@
 			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 @@
 								}
 								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 @@
 		}
 		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 @@
 							/* 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 @@
 					/* 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 @@
 
 	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 @@
 	
 	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 @@
 		
 		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 @@
 				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 @@
 				}
 				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,15 +2101,9 @@
 				}
 				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;
@@ -2167,11 +2115,13 @@
 				}
 				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 @@
 			}
 			ast_frfree(f);
 			if (cnf->recording == MEETME_RECORD_TERMINATE) {
-				ast_mutex_lock(&conflock);
-				ast_mutex_unlock(&conflock);
 				break;
 			}
 		}

Modified: branches/1.2/include/asterisk/lock.h
URL: http://svn.digium.com/view/asterisk/branches/1.2/include/asterisk/lock.h?view=diff&rev=55750&r1=55749&r2=55750
==============================================================================
--- branches/1.2/include/asterisk/lock.h (original)
+++ branches/1.2/include/asterisk/lock.h Tue Feb 20 18:19:14 2007
@@ -666,4 +666,31 @@
 #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 */

Modified: branches/1.2/utils.c
URL: http://svn.digium.com/view/asterisk/branches/1.2/utils.c?view=diff&rev=55750&r1=55749&r2=55750
==============================================================================
--- branches/1.2/utils.c (original)
+++ branches/1.2/utils.c Tue Feb 20 18:19:14 2007
@@ -907,3 +907,14 @@
 #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;
+}



More information about the asterisk-commits mailing list