[asterisk-commits] oej: branch oej/multiparking r55373 - /team/oej/multiparking/res/res_features.c

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Sun Feb 18 13:55:19 MST 2007


Author: oej
Date: Sun Feb 18 14:55:18 2007
New Revision: 55373

URL: http://svn.digium.com/view/asterisk?view=rev&rev=55373
Log:
- Move from AST LIST to AST Objects
- Implement read/write locks for parkinglots and remove some of the old
  locks

Modified:
    team/oej/multiparking/res/res_features.c

Modified: team/oej/multiparking/res/res_features.c
URL: http://svn.digium.com/view/asterisk/team/oej/multiparking/res/res_features.c?view=diff&rev=55373&r1=55372&r2=55373
==============================================================================
--- team/oej/multiparking/res/res_features.c (original)
+++ team/oej/multiparking/res/res_features.c Sun Feb 18 14:55:18 2007
@@ -58,6 +58,7 @@
 #include "asterisk/adsi.h"
 #include "asterisk/devicestate.h"
 #include "asterisk/monitor.h"
+#include "asterisk/astobj.h"
 
 #define DEFAULT_PARK_TIME 45000				/*!< Default parking time */
 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000		
@@ -97,7 +98,7 @@
 
 /*! \brief Structure for parking lots in a linked list. */
 struct ast_parkinglot {
-	char name[AST_MAX_EXTENSION];			/*!< Name for this lot (used in other configs) */
+	ASTOBJ_COMPONENTS(struct ast_parkinglot);	/*!< various object stuff, including ->name */
 	char parking_con[AST_MAX_EXTENSION];		/*!< Context for which parking is made accessible */
 	char parking_con_dial[AST_MAX_EXTENSION];	/*!< Context for dialback for parking (KLUDGE) */
 	int parking_start;				/*!< First available extension for parking */
@@ -106,10 +107,11 @@
 	int parkfindnext;
 	int parkingtime;				/*!< Default parking time */
 	struct parkeduser *occupiedlots;
-	AST_LIST_ENTRY(ast_parkinglot) list;		/*!< List entry */
 };
 
-static AST_LIST_HEAD_STATIC(parkinglots, ast_parkinglot);
+struct ast_parkinglot_list {
+	ASTOBJ_CONTAINER_COMPONENTS(struct ast_parkinglot);
+} parkinglots;
 
 struct ast_parkinglot *default_parkinglot;
 static int comebacktoorigin = 1;
@@ -173,6 +175,14 @@
 
 static pthread_t parking_thread;
 
+/* Forward declarations */
+static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
+static void parkinglot_unref(struct ast_parkinglot *parkinglot);
+static void parkinglot_destroy(struct ast_parkinglot *ruin);
+int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds);
+int ast_park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, struct ast_parkinglot *parkinglot);
+struct ast_parkinglot *find_parkinglot(const char *name);
+
 
 char *ast_parking_ext(void)
 {
@@ -191,9 +201,6 @@
 	struct ast_channel *peer;
 };
 
-/* Forward declarations */
-int ast_park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, struct ast_parkinglot *parkinglot);
-struct ast_parkinglot *find_parkinglot(const char *name);
 
 /*! \brief store context, priority and extension */
 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
@@ -369,22 +376,25 @@
 	if (!parkinglot)
 		parkinglot = default_parkinglot;
 
+	parkinglot_addref(parkinglot);
 	if (option_debug)
 		ast_log(LOG_DEBUG, "Parkinglot: %s\n", parkinglot->name);
 
 	
 	/* Allocate memory for parking data */
-	if (!(pu = ast_calloc(1, sizeof(*pu)))) 
+	if (!(pu = ast_calloc(1, sizeof(*pu)))) {
+		parkinglot_unref(parkinglot);
 		return -1;
-
-	/* Lock parking lot */
-	ast_mutex_lock(&parking_lock);
+	}
+	ASTOBJ_WRLOCK(parkinglot);
 
 	/* Check for channel variable PARKINGEXTEN */
 	parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
 	if (!ast_strlen_zero(parkingexten)) {
 		if (ast_exists_extension(NULL, parkinglot->parking_con, parkingexten, 1, NULL)) {
 			ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con);
+			parkinglot_unref(parkinglot);
+			ASTOBJ_UNLOCK(parkinglot);
 			return 0;	/* Continue execution if possible */
 		}
 		ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten));
@@ -407,6 +417,8 @@
 			ast_log(LOG_WARNING, "No more parking spaces in parking lot \"%s\"\n", parkinglot->name);
 			free(pu);
 			ast_mutex_unlock(&parking_lock);
+			parkinglot_unref(parkinglot);
+			ASTOBJ_UNLOCK(parkinglot);
 			return -1;
 		}
 		/* Set pointer for next parking */
@@ -443,6 +455,7 @@
 	pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
 	pu->next = parkinglot->occupiedlots;
 	parkinglot->occupiedlots = pu;
+	ASTOBJ_UNLOCK(parkinglot);
 
 	/* If parking a channel directly, don't quiet yet get parking running on it */
 	if (peer == chan) 
@@ -1591,88 +1604,117 @@
 		);
 }
 
-/*! \brief Take care of parked calls and unpark them if needed */
-static void *do_parking_thread(void *ignore)
-{
-	struct ast_parkinglot *curlot;
-	char parkingslot[AST_MAX_EXTENSION];
-	fd_set rfds, efds;	/* results from previous select, to be preserved across loops. */
-
-	FD_ZERO(&rfds);
-	FD_ZERO(&efds);
-
-	for (;;) {
-		struct parkeduser *pu, *pl, *pt = NULL;
-		int ms = -1;	/* select timeout, uninitialized */
-		int max = -1;	/* max fd, none there yet */
-		fd_set nrfds, nefds;	/* args for the next select */
-		FD_ZERO(&nrfds);
-		FD_ZERO(&nefds);
-
-		ast_mutex_lock(&parking_lock);
-		pl = NULL;
-
-		/* We need to do this for every parking lot */
-		AST_LIST_TRAVERSE(&parkinglots, curlot, list) {
-			pu = curlot->occupiedlots;
+/*! \brief Run management on parkinglots, called once per parkinglot */
+int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds)
+{
+	int ms = -1;	/* select timeout, uninitialized */
+	int max = -1;	/* max fd, none there yet */
+	struct parkeduser *pu, *pl = NULL, *pt = NULL;
+	int res = 0;
+
+	parkinglot_addref(curlot);
+	pu = curlot->occupiedlots;
 		
-			while(pu) {
-				struct ast_channel *chan = pu->chan;	/* shorthand */
-				int tms;        /* timeout for this item */
-				int x;          /* fd index in channel */
-				struct ast_context *con;
-
-				if (pu->notquiteyet) { /* Pretend this one isn't here yet */
-					pl = pu;
-					pu = pu->next;
+	while(pu) {
+		struct ast_channel *chan = pu->chan;	/* shorthand */
+		int tms;        /* timeout for this item */
+		int x;          /* fd index in channel */
+		struct ast_context *con;
+
+		if (pu->notquiteyet) { /* Pretend this one isn't here yet */
+			pl = pu;
+			pu = pu->next;
+			continue;
+		}
+		tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
+		if (tms > pu->parkingtime) {
+			/* Stop music on hold */
+			ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
+			/* Get chan, exten from derived kludge */
+			if (pu->peername[0]) {
+				char *peername = ast_strdupa(pu->peername);
+				char *cp = strrchr(peername, '-');
+
+				if (cp) 
+					*cp = 0;
+				con = ast_context_find(pu->parkinglot->parking_con_dial);
+				if (!con)
+					con = ast_context_create(NULL, pu->parkinglot->parking_con_dial, registrar);
+				if (!con) 
+					ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con_dial);
+				if (con) {
+					char returnexten[AST_MAX_EXTENSION];
+
+					snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
+					ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
+				}
+				if (comebacktoorigin)
+					set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername, 1);
+				else {
+					char parkingslot[AST_MAX_EXTENSION];
+					ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum);
+					snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
+					pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
+					set_c_e_p(chan, "parkedcallstimeout", peername, 1);
+				}
+
+			} else {
+				/* They've been waiting too long, send them back to where they came.  Theoretically they
+			   	should have their original extensions and such, but we copy to be on the safe side */
+				set_c_e_p(chan, pu->context, pu->exten, pu->priority);
+
+			}
+			post_manager_event("ParkedCallTimeOut", pu);
+
+			if (option_verbose > 1) 
+				ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context, pu->chan->exten, pu->chan->priority);
+			/* Start up the PBX, or hang them up */
+			if (ast_pbx_start(chan))  {
+				ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
+				ast_hangup(chan);
+			}
+			/* And take them out of the parking lot */
+			if (pl) 
+				pl->next = pu->next;
+			else
+				curlot->occupiedlots = pu->next;
+			pt = pu;
+			pu = pu->next;
+			con = ast_context_find(pt->parkinglot->parking_con);
+			if (con) {
+				if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
+					ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
+				else
+					notify_metermaids(pt->parkingexten, curlot->parking_con);
+			} else
+				ast_log(LOG_WARNING, "Whoa, no parking context?\n");
+			free(pt);
+			parkinglot_unref(curlot);
+		} else {	/* still within parking time, process descriptors */
+			for (x = 0; x < AST_MAX_FDS; x++) {
+				struct ast_frame *f;
+
+				if ((chan->fds[x] == -1) && (!FD_ISSET(chan->fds[x], rfds) && !FD_ISSET(pu->chan->fds[x], efds))) 
 					continue;
-				}
-				tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
-				if (tms > pu->parkingtime) {
-					/* Stop music on hold */
-					ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
-					/* Get chan, exten from derived kludge */
-					if (pu->peername[0]) {
-						char *peername = ast_strdupa(pu->peername);
-						char *cp = strrchr(peername, '-');
-
-						if (cp) 
-							*cp = 0;
-						con = ast_context_find(pu->parkinglot->parking_con_dial);
-						if (!con)
-							con = ast_context_create(NULL, pu->parkinglot->parking_con_dial, registrar);
-						if (!con) 
-							ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con_dial);
-						if (con) {
-							char returnexten[AST_MAX_EXTENSION];
-
-							snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
-							ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
-						}
-						if (comebacktoorigin)
-							set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername, 1);
-						else {
-							ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum);
-							snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
-							pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
-							set_c_e_p(chan, "parkedcallstimeout", peername, 1);
-						}
-
-					} else {
-						/* They've been waiting too long, send them back to where they came.  Theoretically they
-					   	should have their original extensions and such, but we copy to be on the safe side */
-						set_c_e_p(chan, pu->context, pu->exten, pu->priority);
-
-					}
-					post_manager_event("ParkedCallTimeOut", pu);
-
+
+				if (FD_ISSET(chan->fds[x], efds))
+					ast_set_flag(chan, AST_FLAG_EXCEPTION);
+				else
+					ast_clear_flag(chan, AST_FLAG_EXCEPTION);
+				chan->fdno = x;
+
+				/* See if they need servicing */
+				f = ast_read(pu->chan);
+				/* Hangup? */
+				if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
+					if (f)
+						ast_frfree(f);
+					post_manager_event("ParkedCallGiveUp", pu);
+
+					/* There's a problem, hang them up*/
 					if (option_verbose > 1) 
-						ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context, pu->chan->exten, pu->chan->priority);
-					/* Start up the PBX, or hang them up */
-					if (ast_pbx_start(chan))  {
-						ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
-						ast_hangup(chan);
-					}
+						ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
+					ast_hangup(chan);
 					/* And take them out of the parking lot */
 					if (pl) 
 						pl->next = pu->next;
@@ -1680,90 +1722,75 @@
 						curlot->occupiedlots = pu->next;
 					pt = pu;
 					pu = pu->next;
-					con = ast_context_find(pt->parkinglot->parking_con);
+					con = ast_context_find(curlot->parking_con);
 					if (con) {
 						if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
-							ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
+							ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
 						else
 							notify_metermaids(pt->parkingexten, curlot->parking_con);
 					} else
-						ast_log(LOG_WARNING, "Whoa, no parking context?\n");
+						ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name);
 					free(pt);
-				} else {	/* still within parking time, process descriptors */
-					for (x = 0; x < AST_MAX_FDS; x++) {
-						struct ast_frame *f;
-
-						if ((chan->fds[x] == -1) && (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(pu->chan->fds[x], &efds))) 
-							continue;
-
-						if (FD_ISSET(chan->fds[x], &efds))
-							ast_set_flag(chan, AST_FLAG_EXCEPTION);
-						else
-							ast_clear_flag(chan, AST_FLAG_EXCEPTION);
-						chan->fdno = x;
-
-						/* See if they need servicing */
-						f = ast_read(pu->chan);
-						/* Hangup? */
-						if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
-							if (f)
-								ast_frfree(f);
-							post_manager_event("ParkedCallGiveUp", pu);
-
-							/* There's a problem, hang them up*/
-							if (option_verbose > 1) 
-								ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
-							ast_hangup(chan);
-							/* And take them out of the parking lot */
-							if (pl) 
-								pl->next = pu->next;
-							else
-								curlot->occupiedlots = pu->next;
-							pt = pu;
-							pu = pu->next;
-							con = ast_context_find(curlot->parking_con);
-							if (con) {
-								if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
-									ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
-								else
-									notify_metermaids(pt->parkingexten, curlot->parking_con);
-							} else
-								ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name);
-							free(pt);
-							break;
-						} else {
-							/* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
-							ast_frfree(f);
-							if (pu->moh_trys < 3 && !chan->generatordata) {
-								if (option_debug)
-									ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting on channel %s.\n", chan->name);
-								ast_indicate_data(chan, AST_CONTROL_HOLD, 
-									S_OR(parkmohclass, NULL),
-									!ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
-								pu->moh_trys++;
-							}
-							goto std;	/* XXX Ick: jumping into an else statement??? XXX */
-						}
-					} /* End for */
-					if (x >= AST_MAX_FDS) {
-	std:					for (x=0; x<AST_MAX_FDS; x++) {	/* mark fds for next round */
-							if (chan->fds[x] > -1) {
-								FD_SET(chan->fds[x], &nrfds);
-								FD_SET(chan->fds[x], &nefds);
-								if (chan->fds[x] > max)
-									max = chan->fds[x];
-							}
-						}
-						/* Keep track of our shortest wait */
-						if (tms < ms || ms < 0)
-							ms = tms;
-						pl = pu;
-						pu = pu->next;
+					parkinglot_unref(curlot);
+					break;
+				} else {
+					/* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
+					ast_frfree(f);
+					if (pu->moh_trys < 3 && !chan->generatordata) {
+						if (option_debug)
+							ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting on channel %s.\n", chan->name);
+						ast_indicate_data(chan, AST_CONTROL_HOLD, 
+							S_OR(parkmohclass, NULL),
+							!ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
+						pu->moh_trys++;
+					}
+					goto std;	/* XXX Ick: jumping into an else statement??? XXX */
+				}
+			} /* End for */
+			if (x >= AST_MAX_FDS) {
+std:				for (x=0; x<AST_MAX_FDS; x++) {	/* mark fds for next round */
+					if (chan->fds[x] > -1) {
+						FD_SET(chan->fds[x], nrfds);
+						FD_SET(chan->fds[x], nefds);
+						if (chan->fds[x] > max)
+							max = chan->fds[x];
 					}
 				}
-			} /* end while */
-		}
-		ast_mutex_unlock(&parking_lock);
+				/* Keep track of our shortest wait */
+				if (tms < ms || ms < 0)
+					ms = tms;
+				pl = pu;
+				pu = pu->next;
+			}
+		}
+	}
+	return res;
+}
+
+/*! \brief Take care of parked calls and unpark them if needed */
+static void *do_parking_thread(void *ignore)
+{
+	fd_set rfds, efds;	/* results from previous select, to be preserved across loops. */
+	int ms = -1;	/* select timeout, uninitialized */
+	int max = -1;	/* max fd, none there yet */
+
+	FD_ZERO(&rfds);
+	FD_ZERO(&efds);
+
+	for (;;) {
+		int res = 0;
+
+		fd_set nrfds, nefds;	/* args for the next select */
+		FD_ZERO(&nrfds);
+		FD_ZERO(&nefds);
+
+		/* We need to do this for every parking lot */
+		ASTOBJ_CONTAINER_TRAVERSE(&parkinglots, 1, do {
+			
+			ASTOBJ_WRLOCK(iterator);
+			res = manage_parkinglot(iterator, &rfds, &efds, &nrfds, &nefds);
+			ASTOBJ_UNLOCK(iterator);
+		} while (0) );
 		rfds = nrfds;
 		efds = nefds;
 		{
@@ -1784,15 +1811,11 @@
 	if (ast_strlen_zero(name))
 		return NULL;
 
-	AST_LIST_TRAVERSE(&parkinglots, parkinglot, list) {
-		if (!strcasecmp(parkinglot->name, name)) {
-			if (option_debug)
-				ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name);
-			return(parkinglot);
-		}
-	}
-
-	/* We did not find a parking lot */
+	parkinglot = ASTOBJ_CONTAINER_FIND(&parkinglots, name);
+
+	if (parkinglot && option_debug)
+		ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name);
+
 	return parkinglot;
 }
 
@@ -1863,6 +1886,8 @@
 			ast_log(LOG_DEBUG, "Using parking lot: %s\n", parkinglotname);
 		parkinglot = find_parkinglot(parkinglotname);	
 	}
+	ASTOBJ_WRLOCK(parkinglot);
+	ast_mutex_unlock(&parking_lock);
 	pu = parkinglot->occupiedlots;
 	while(pu) {
 		if (pu->parkingnum == park) {
@@ -1875,7 +1900,6 @@
 		pl = pu;
 		pu = pu->next;
 	}
-	ast_mutex_unlock(&parking_lock);
 	if (pu) {
 		peer = pu->chan;
 		con = ast_context_find(pu->parkinglot->parking_con);
@@ -1929,6 +1953,7 @@
 			if (error) {
 				ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
 				ast_hangup(peer);
+				ASTOBJ_UNLOCK(parkinglot);
 				return -1;
 			}
 		} else
@@ -1937,6 +1962,7 @@
 		res = ast_channel_make_compatible(chan, peer);
 		if (res < 0) {
 			ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
+			ASTOBJ_UNLOCK(parkinglot);
 			ast_hangup(peer);
 			return -1;
 		}
@@ -1960,8 +1986,10 @@
 		ast_cdr_setdestchan(chan->cdr, peer->name);
 
 		/* Simulate the PBX hanging up */
-		if (res != AST_PBX_NO_HANGUP_PEER)
+		if (res != AST_PBX_NO_HANGUP_PEER) {
+			ASTOBJ_UNLOCK(parkinglot);
 			ast_hangup(peer);
+		}
 		return res;
 	} else {
 		/*! \todo XXX Play a message XXX */
@@ -1971,6 +1999,7 @@
 			ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
 		res = -1;
 	}
+	ASTOBJ_UNLOCK(parkinglot);
 
 	ast_module_user_remove(u);
 
@@ -1988,7 +2017,6 @@
 	int fcount;
 	struct ast_call_feature *feature;
 	char format[] = "%-25s %-7s %-7s\n";
-	struct ast_parkinglot *parkinglot;
 
 	ast_cli(fd, format, "Builtin Feature", "Default", "Current");
 	ast_cli(fd, format, "---------------", "-------", "-------");
@@ -2019,12 +2047,14 @@
 	ast_cli(fd, "------------\n");
 	ast_cli(fd,"%-20s:	%s\n", "Parking extension", parking_ext);
 
-	AST_LIST_TRAVERSE(&parkinglots, parkinglot, list) {
-		ast_cli(fd, "%-24s   :      %s\n", "Parking lot", parkinglot->name);
-		ast_cli(fd,"    %-24s:	%s\n", "Parking context", parkinglot->parking_con);
-		ast_cli(fd,"    %-24s:	%d-%d\n", "Parked call extensions", parkinglot->parking_start, parkinglot->parking_stop);
-	
-	}
+	ASTOBJ_CONTAINER_TRAVERSE(&parkinglots, 1, do {
+		ASTOBJ_RDLOCK(iterator);
+		ast_cli(fd, "%-24s   :      %s\n", "Parking lot", iterator->name);
+		ast_cli(fd,"    %-24s:	%s\n", "Parking context", iterator->parking_con);
+		ast_cli(fd,"    %-24s:	%d-%d\n", "Parked call extensions", iterator->parking_start, iterator->parking_stop);
+		ASTOBJ_UNLOCK(iterator);
+	
+	} while (0) );
 	ast_cli(fd,"\n");
 	
 	return RESULT_SUCCESS;
@@ -2038,19 +2068,18 @@
 {
 	struct parkeduser *cur;
 	int numparked = 0;
-	struct ast_parkinglot *parkinglot;
-	
 
 	ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
 		, "Context", "Extension", "Pri", "Timeout");
 
 	ast_mutex_lock(&parking_lock);
 
-	AST_LIST_TRAVERSE(&parkinglots, parkinglot, list) {
+	ASTOBJ_CONTAINER_TRAVERSE(&parkinglots, 1, do {
 		int lotparked = 0;
-		cur = parkinglot->occupiedlots;
+		ASTOBJ_RDLOCK(iterator);
+		cur = iterator->occupiedlots;
 		if (cur)
-			ast_cli(fd, "*** Parking lot: %s\n", parkinglot->name);
+			ast_cli(fd, "*** Parking lot: %s\n", iterator->name);
 		while(cur) {
 			ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
 				,cur->parkingexten, cur->chan->name, cur->context, cur->exten
@@ -2059,9 +2088,10 @@
 			lotparked++;
 		}
 		if (lotparked)
-			ast_cli(fd, "   %d parked call%s in parking lot %s\n", lotparked, (lotparked != 1) ? "s" : "", parkinglot->name);
+			ast_cli(fd, "   %d parked call%s in parking lot %s\n", lotparked, (lotparked != 1) ? "s" : "", iterator->name);
 		numparked += lotparked;
-	}
+		ASTOBJ_UNLOCK(iterator);
+	} while (0) );
 	ast_cli(fd, "---\n%d parked call%s in total.\n", numparked, (numparked != 1) ? "s" : "");
 	ast_mutex_unlock(&parking_lock);
 	return RESULT_SUCCESS;
@@ -2087,7 +2117,6 @@
 	struct parkeduser *cur;
 	const char *id = astman_get_header(m, "ActionID");
 	char idText[256] = "";
-	struct ast_parkinglot *parkinglot;
 
 	if (id && !ast_strlen_zero(id))
 		snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
@@ -2097,8 +2126,9 @@
 	/* Do we need to lock all of parking? */
         ast_mutex_lock(&parking_lock);
 
-	AST_LIST_TRAVERSE(&parkinglots, parkinglot, list) {
-        	cur=parkinglot->occupiedlots;
+	ASTOBJ_CONTAINER_TRAVERSE(&parkinglots, 1, do {
+		ASTOBJ_RDLOCK(iterator);
+        	cur=iterator->occupiedlots;
         	while(cur) {
 			astman_append(s, "Event: ParkedCall\r\n"
 				"Exten: %d\r\n"
@@ -2111,7 +2141,7 @@
 				"%s"
 				"\r\n",
                         	cur->parkingnum, cur->chan->name, cur->peername,
-				parkinglot->name,
+				iterator->name,
                         	(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL),
 				S_OR(cur->chan->cid.cid_num, ""),	/* XXX in other places it is <unknown> */
 				S_OR(cur->chan->cid.cid_name, ""),
@@ -2119,7 +2149,8 @@
 
 			cur = cur->next;
 		}
-	}
+		ASTOBJ_UNLOCK(iterator);
+	} while (0) );
 
 	astman_append(s,
 		"Event: ParkedCallsComplete\r\n"
@@ -2228,6 +2259,22 @@
 	return res;
 }
 
+/*! \brief Unreference parkinglot object. If no more references,
+	then go ahead and delete it */
+static void parkinglot_unref(struct ast_parkinglot *parkinglot) 
+{
+	if (option_debug > 2)
+		ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, parkinglot->refcount - 1);
+	ASTOBJ_UNREF(parkinglot, parkinglot_destroy);
+}
+
+static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot)
+{
+	if (option_debug > 2)
+		ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, parkinglot->refcount + 1);
+	return ASTOBJ_REF(parkinglot);
+}
+
 /*! \brief Allocate parking lot structure */
 static struct ast_parkinglot *create_parkinglot(char *name)
 {
@@ -2239,18 +2286,21 @@
 	newlot = ast_calloc(1, sizeof(*newlot));
 	if (!newlot)
 		return NULL;
+
+	ASTOBJ_INIT(newlot);
 	ast_copy_string(newlot->name, name, sizeof(newlot->name));
 
 	return newlot;
 }
 
 /*! \brief Destroy a parking lot */
-static void destroy_parkinglot(struct ast_parkinglot *ruin)
+static void parkinglot_destroy(struct ast_parkinglot *ruin)
 {
 	struct ast_context *con;
 	con = ast_context_find(ruin->parking_con);
 	if (con)
 		ast_context_destroy(con, registrar);
+	ASTOBJ_CONTAINER_UNLINK(&parkinglots, ruin);	/* Remove from parkinglot list */
 	free(ruin);
 }
 
@@ -2264,11 +2314,17 @@
 	int error = 0;
 	int start = 0, end = 0;
 
-	/* Check if parkinglot with this name already exists */
-	/* OEJ */
-	parkinglot = create_parkinglot(name);
+	parkinglot = find_parkinglot(name);
+	if (parkinglot)
+		ASTOBJ_UNMARK(parkinglot);
+	else
+		parkinglot = create_parkinglot(name);
+
 	if (!parkinglot)
 		return NULL;
+
+	ASTOBJ_WRLOCK(parkinglot);
+
 	if (option_debug)
 		ast_log(LOG_DEBUG, "Building parking lot %s\n", name);
 	
@@ -2317,16 +2373,20 @@
 	if (ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), ast_free, registrar) == -1)
 		error = 1;
 
+	ASTOBJ_UNLOCK(parkinglot);
+
 	if (error) {
 		ast_log(LOG_WARNING, "Parking %s not open for business. Configuration error.\n", name);
-		destroy_parkinglot(parkinglot);
+		parkinglot_destroy(parkinglot);
 		return NULL;
 	}
 	if (option_debug)
 		ast_log(LOG_DEBUG, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end);
 
+
 	/* Move it into the list */
-	AST_LIST_INSERT_TAIL(&parkinglots, parkinglot, list);
+	ASTOBJ_CONTAINER_LINK(&parkinglots, parkinglot);
+	parkinglot_unref(parkinglot);
 
 	return parkinglot;
 	
@@ -2366,6 +2426,7 @@
 	} else {
 		default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
 		if (default_parkinglot) {
+			ASTOBJ_WRLOCK(default_parkinglot);
 			default_parkinglot->parking_start = 701;
 			default_parkinglot->parking_stop = 750;
 			default_parkinglot->parking_offset = 0;
@@ -2518,6 +2579,9 @@
 		}
 	}
 
+	if (default_parkinglot)
+		ASTOBJ_UNLOCK(default_parkinglot);
+
 	unmap_features();
 	for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
 		if (remap_feature(var->name, var->value))
@@ -2650,27 +2714,22 @@
 
 static int reload(void)
 {
+	int res;
 
 	/* Release parking lot list */
-	if (!AST_LIST_EMPTY(&parkinglots) ) {
-		struct ast_parkinglot *park;
-		AST_LIST_LOCK(&parkinglots);
-		while ((park = AST_LIST_REMOVE_HEAD(&parkinglots, list))) {
-			destroy_parkinglot(park);
-		}
-		AST_LIST_UNLOCK(&parkinglots);
-	}
+	ASTOBJ_CONTAINER_MARKALL(&parkinglots);
 
 	/* Reload configuration */
-	return load_config();
+	res = load_config();
+	
+	ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy);
+	return res;
 }
 
 static int load_module(void)
 {
 	int res;
 	
-	AST_LIST_HEAD_INIT(&parkinglots);
-
 	if ((res = load_config()))
 		return res;
 	ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));



More information about the asterisk-commits mailing list