[asterisk-commits] dlee: branch dlee/stasis-cache-split r394039 - in /team/dlee/stasis-cache-spl...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jul 10 21:08:33 CDT 2013


Author: dlee
Date: Wed Jul 10 21:08:31 2013
New Revision: 394039

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=394039
Log:
Merged revisions 393896-394037 from http://svn.asterisk.org/svn/asterisk/trunk

Added:
    team/dlee/stasis-cache-split/contrib/scripts/sip_to_res_sip/
      - copied from r394037, trunk/contrib/scripts/sip_to_res_sip/
Modified:
    team/dlee/stasis-cache-split/   (props changed)
    team/dlee/stasis-cache-split/apps/app_meetme.c
    team/dlee/stasis-cache-split/channels/chan_gulp.c
    team/dlee/stasis-cache-split/configs/sla.conf.sample
    team/dlee/stasis-cache-split/include/asterisk/lock.h
    team/dlee/stasis-cache-split/include/asterisk/manager.h
    team/dlee/stasis-cache-split/main/xmldoc.c
    team/dlee/stasis-cache-split/res/res_sip_outbound_registration.c
    team/dlee/stasis-cache-split/res/res_stasis_http_asterisk.c
    team/dlee/stasis-cache-split/res/res_stasis_http_channels.c
    team/dlee/stasis-cache-split/res/stasis_http/ari_model_validators.c
    team/dlee/stasis-cache-split/res/stasis_http/ari_model_validators.h
    team/dlee/stasis-cache-split/rest-api/api-docs/asterisk.json
    team/dlee/stasis-cache-split/rest-api/api-docs/channels.json
    team/dlee/stasis-cache-split/tests/test_cel.c

Propchange: team/dlee/stasis-cache-split/
------------------------------------------------------------------------------
Binary property 'branch-11-merged' - no diff available.

Propchange: team/dlee/stasis-cache-split/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Wed Jul 10 21:08:31 2013
@@ -1,1 +1,1 @@
-/trunk:1-393884
+/trunk:1-394038

Modified: team/dlee/stasis-cache-split/apps/app_meetme.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-cache-split/apps/app_meetme.c?view=diff&rev=394039&r1=394038&r2=394039
==============================================================================
--- team/dlee/stasis-cache-split/apps/app_meetme.c (original)
+++ team/dlee/stasis-cache-split/apps/app_meetme.c Wed Jul 10 21:08:31 2013
@@ -961,17 +961,26 @@
 	/*! This option uses the values in the sla_hold_access enum and sets the
 	 * access control type for hold on this station. */
 	unsigned int hold_access:1;
-	/*! Use count for inside sla_station_exec */
-	unsigned int ref_count;
+	/*! Mark used during reload processing */
+	unsigned int mark:1;
 };
 
+/*!
+ * \brief A reference to a station
+ *
+ * This struct looks near useless at first glance.  However, its existence
+ * in the list of stations in sla_trunk means that this station references
+ * that trunk.  We use the mark to keep track of whether it needs to be
+ * removed from the sla_trunk's list of stations during a reload.
+ */
 struct sla_station_ref {
 	AST_LIST_ENTRY(sla_station_ref) entry;
 	struct sla_station *station;
+	/*! Mark used during reload processing */
+	unsigned int mark:1;
 };
 
 struct sla_trunk {
-	AST_RWLIST_ENTRY(sla_trunk) entry;
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(name);
 		AST_STRING_FIELD(device);
@@ -995,10 +1004,16 @@
 	/*! Whether this trunk is currently on hold, meaning that once a station
 	 *  connects to it, the trunk channel needs to have UNHOLD indicated to it. */
 	unsigned int on_hold:1;
-	/*! Use count for inside sla_trunk_exec */
-	unsigned int ref_count;
+	/*! Mark used during reload processing */
+	unsigned int mark:1;
 };
 
+/*!
+ * \brief A station's reference to a trunk
+ *
+ * An sla_station keeps a list of trunk_refs.  This holds metadata about the
+ * stations usage of the trunk.
+ */
 struct sla_trunk_ref {
 	AST_LIST_ENTRY(sla_trunk_ref) entry;
 	struct sla_trunk *trunk;
@@ -1012,10 +1027,12 @@
 	 *  station.  This takes higher priority than a ring delay set at
 	 *  the station level. */
 	unsigned int ring_delay;
+	/*! Mark used during reload processing */
+	unsigned int mark:1;
 };
 
-static AST_RWLIST_HEAD_STATIC(sla_stations, sla_station);
-static AST_RWLIST_HEAD_STATIC(sla_trunks, sla_trunk);
+static struct ao2_container *sla_stations;
+static struct ao2_container *sla_trunks;
 
 static const char sla_registrar[] = "SLA";
 
@@ -1027,10 +1044,6 @@
 	SLA_EVENT_DIAL_STATE,
 	/*! The state of a ringing trunk has changed */
 	SLA_EVENT_RINGING_TRUNK,
-	/*! A reload of configuration has been requested */
-	SLA_EVENT_RELOAD,
-	/*! Poke the SLA thread so it can check if it can perform a reload */
-	SLA_EVENT_CHECK_RELOAD,
 };
 
 struct sla_event {
@@ -1086,8 +1099,6 @@
 	/*! Attempt to handle CallerID, even though it is known not to work
 	 *  properly in some situations. */
 	unsigned int attempt_callerid:1;
-	/*! A reload has been requested */
-	unsigned int reload:1;
 } sla = {
 	.thread = AST_PTHREADT_NULL,
 };
@@ -2117,7 +2128,8 @@
 
 static char *sla_show_trunks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	const struct sla_trunk *trunk;
+	struct ao2_iterator i;
+	struct sla_trunk *trunk;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -2135,12 +2147,17 @@
 	            "=== Configured SLA Trunks ===================================\n"
 	            "=============================================================\n"
 	            "===\n");
-	AST_RWLIST_RDLOCK(&sla_trunks);
-	AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
+	i = ao2_iterator_init(sla_trunks, 0);
+	for (; (trunk = ao2_iterator_next(&i)); ao2_ref(trunk, -1)) {
 		struct sla_station_ref *station_ref;
 		char ring_timeout[16] = "(none)";
-		if (trunk->ring_timeout)
+
+		ao2_lock(trunk);
+
+		if (trunk->ring_timeout) {
 			snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
+		}
+
 		ast_cli(a->fd, "=== ---------------------------------------------------------\n"
 		            "=== Trunk Name:       %s\n"
 		            "=== ==> Device:       %s\n"
@@ -2154,13 +2171,16 @@
 		            ring_timeout,
 		            trunk->barge_disabled ? "No" : "Yes",
 		            sla_hold_str(trunk->hold_access));
-		AST_RWLIST_RDLOCK(&sla_stations);
-		AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
+
+		AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
 			ast_cli(a->fd, "===    ==> Station name: %s\n", station_ref->station->name);
-		AST_RWLIST_UNLOCK(&sla_stations);
+		}
+
 		ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
-	}
-	AST_RWLIST_UNLOCK(&sla_trunks);
+
+		ao2_unlock(trunk);
+	}
+	ao2_iterator_destroy(&i);
 	ast_cli(a->fd, "=============================================================\n\n");
 
 	return CLI_SUCCESS;
@@ -2182,7 +2202,8 @@
 
 static char *sla_show_stations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	const struct sla_station *station;
+	struct ao2_iterator i;
+	struct sla_station *station;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -2200,11 +2221,14 @@
 	            "=== Configured SLA Stations =================================\n"
 	            "=============================================================\n"
 	            "===\n");
-	AST_RWLIST_RDLOCK(&sla_stations);
-	AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
+	i = ao2_iterator_init(sla_stations, 0);
+	for (; (station = ao2_iterator_next(&i)); ao2_ref(station, -1)) {
 		struct sla_trunk_ref *trunk_ref;
 		char ring_timeout[16] = "(none)";
 		char ring_delay[16] = "(none)";
+
+		ao2_lock(station);
+
 		if (station->ring_timeout) {
 			snprintf(ring_timeout, sizeof(ring_timeout), 
 				"%u", station->ring_timeout);
@@ -2225,7 +2249,6 @@
 		            S_OR(station->autocontext, "(none)"), 
 		            ring_timeout, ring_delay,
 		            sla_hold_str(station->hold_access));
-		AST_RWLIST_RDLOCK(&sla_trunks);
 		AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
 			if (trunk_ref->ring_timeout) {
 				snprintf(ring_timeout, sizeof(ring_timeout),
@@ -2245,11 +2268,12 @@
 			            trunkstate2str(trunk_ref->state),
 			            ring_timeout, ring_delay);
 		}
-		AST_RWLIST_UNLOCK(&sla_trunks);
 		ast_cli(a->fd, "=== ---------------------------------------------------------\n"
 		            "===\n");
-	}
-	AST_RWLIST_UNLOCK(&sla_stations);
+
+		ao2_unlock(station);
+	}
+	ao2_iterator_destroy(&i);
 	ast_cli(a->fd, "============================================================\n"
 	            "\n");
 
@@ -2393,11 +2417,16 @@
 	struct sla_event *event;
 
 	if (sla.thread == AST_PTHREADT_NULL) {
+		ao2_ref(station, -1);
+		ao2_ref(trunk_ref, -1);
 		return;
 	}
 
-	if (!(event = ast_calloc(1, sizeof(*event))))
+	if (!(event = ast_calloc(1, sizeof(*event)))) {
+		ao2_ref(station, -1);
+		ao2_ref(trunk_ref, -1);
 		return;
+	}
 
 	event->type = type;
 	event->trunk_ref = trunk_ref;
@@ -2431,6 +2460,7 @@
 	struct sla_station *station;
 	struct sla_trunk_ref *trunk_ref = NULL;
 	char *trunk_name;
+	struct ao2_iterator i;
 
 	trunk_name = ast_strdupa(conf->confno);
 	strsep(&trunk_name, "_");
@@ -2439,16 +2469,23 @@
 		return;
 	}
 
-	AST_RWLIST_RDLOCK(&sla_stations);
-	AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
+	i = ao2_iterator_init(sla_stations, 0);
+	while ((station = ao2_iterator_next(&i))) {
+		ao2_lock(station);
 		AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
-			if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
+			if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name)) {
+				ao2_ref(trunk_ref, 1);
 				break;
-		}
-		if (trunk_ref)
+			}
+		}
+		ao2_unlock(station);
+		if (trunk_ref) {
+			/* station reference given to sla_queue_event_full() */
 			break;
-	}
-	AST_RWLIST_UNLOCK(&sla_stations);
+		}
+		ao2_ref(station, -1);
+	}
+	ao2_iterator_destroy(&i);
 
 	if (!trunk_ref) {
 		ast_debug(1, "Trunk not found for event!\n");
@@ -5776,34 +5813,30 @@
 	ast_config_destroy(cfg);
 }
 
-/*! \brief Find an SLA trunk by name
- * \note This must be called with the sla_trunks container locked
+/*!
+ * \internal
+ * \brief Find an SLA trunk by name
  */
 static struct sla_trunk *sla_find_trunk(const char *name)
 {
-	struct sla_trunk *trunk = NULL;
-
-	AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
-		if (!strcasecmp(trunk->name, name))
-			break;
-	}
-
-	return trunk;
-}
-
-/*! \brief Find an SLA station by name
- * \note This must be called with the sla_stations container locked
+	struct sla_trunk tmp_trunk = {
+		.name = name,
+	};
+
+	return ao2_find(sla_trunks, &tmp_trunk, OBJ_POINTER);
+}
+
+/*!
+ * \internal
+ * \brief Find an SLA station by name
  */
 static struct sla_station *sla_find_station(const char *name)
 {
-	struct sla_station *station = NULL;
-
-	AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
-		if (!strcasecmp(station->name, name))
-			break;
-	}
-
-	return station;
+	struct sla_station tmp_station = {
+		.name = name,
+	};
+
+	return ao2_find(sla_stations, &tmp_station, OBJ_POINTER);
 }
 
 static int sla_check_station_hold_access(const struct sla_trunk *trunk,
@@ -5827,9 +5860,11 @@
 	return 0;
 }
 
-/*! \brief Find a trunk reference on a station by name
+/*!
+ * \brief Find a trunk reference on a station by name
  * \param station the station
  * \param name the trunk's name
+ * \pre sla_station is locked
  * \return a pointer to the station's trunk reference.  If the trunk
  *         is not found, it is not idle and barge is disabled, or if
  *         it is on hold and private hold is set, then NULL will be returned.
@@ -5856,16 +5891,32 @@
 		break;
 	}
 
+	if (trunk_ref) {
+		ao2_ref(trunk_ref, 1);
+	}
+
 	return trunk_ref;
 }
 
+static void sla_station_ref_destructor(void *obj)
+{
+	struct sla_station_ref *station_ref = obj;
+
+	if (station_ref->station) {
+		ao2_ref(station_ref->station, -1);
+		station_ref->station = NULL;
+	}
+}
+
 static struct sla_station_ref *sla_create_station_ref(struct sla_station *station)
 {
 	struct sla_station_ref *station_ref;
 
-	if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
+	if (!(station_ref = ao2_alloc(sizeof(*station_ref), sla_station_ref_destructor))) {
 		return NULL;
-
+	}
+
+	ao2_ref(station, 1);
 	station_ref->station = station;
 
 	return station_ref;
@@ -5878,10 +5929,46 @@
 	if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
 		return NULL;
 
+	ao2_ref(station, 1);
 	ringing_station->station = station;
 	ringing_station->ring_begin = ast_tvnow();
 
 	return ringing_station;
+}
+
+static void sla_ringing_station_destroy(struct sla_ringing_station *ringing_station)
+{
+	if (ringing_station->station) {
+		ao2_ref(ringing_station->station, -1);
+		ringing_station->station = NULL;
+	}
+
+	ast_free(ringing_station);
+}
+
+static struct sla_failed_station *sla_create_failed_station(struct sla_station *station)
+{
+	struct sla_failed_station *failed_station;
+
+	if (!(failed_station = ast_calloc(1, sizeof(*failed_station)))) {
+		return NULL;
+	}
+
+	ao2_ref(station, 1);
+	failed_station->station = station;
+	failed_station->last_try = ast_tvnow();
+
+	return failed_station;
+}
+
+static void sla_failed_station_destroy(struct sla_failed_station *failed_station)
+{
+	if (failed_station->station) {
+		ao2_ref(failed_station->station, -1);
+		failed_station->station = NULL;
+	}
+
+	ast_free(failed_station);
 }
 
 static enum ast_device_state sla_state_to_devstate(enum sla_trunk_state state)
@@ -5906,18 +5993,25 @@
 {
 	struct sla_station *station;
 	struct sla_trunk_ref *trunk_ref;
-
-	AST_LIST_TRAVERSE(&sla_stations, station, entry) {
+	struct ao2_iterator i;
+
+	i = ao2_iterator_init(sla_stations, 0);
+	while ((station = ao2_iterator_next(&i))) {
+		ao2_lock(station);
 		AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
 			if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
-				|| trunk_ref == exclude)
+					|| trunk_ref == exclude) {
 				continue;
+			}
 			trunk_ref->state = state;
 			ast_devstate_changed(sla_state_to_devstate(state), AST_DEVSTATE_CACHABLE,
 					     "SLA:%s_%s", station->name, trunk->name);
 			break;
 		}
-	}
+		ao2_unlock(station);
+		ao2_ref(station, -1);
+	}
+	ao2_iterator_destroy(&i);
 }
 
 struct run_station_args {
@@ -5935,8 +6029,8 @@
 
 static void *run_station(void *data)
 {
-	struct sla_station *station;
-	struct sla_trunk_ref *trunk_ref;
+	RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
+	RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
 	struct ast_str *conf_name = ast_str_create(16);
 	struct ast_flags64 conf_flags = { 0 };
 	struct ast_conference *conf;
@@ -5979,6 +6073,8 @@
 	return NULL;
 }
 
+static void sla_ringing_trunk_destroy(struct sla_ringing_trunk *ringing_trunk);
+
 static void sla_stop_ringing_trunk(struct sla_ringing_trunk *ringing_trunk)
 {
 	char buf[80];
@@ -5988,10 +6084,11 @@
 	admin_exec(NULL, buf);
 	sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
 
-	while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
-		ast_free(station_ref);
-
-	ast_free(ringing_trunk);
+	while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry))) {
+		ao2_ref(station_ref, -1);
+	}
+
+	sla_ringing_trunk_destroy(ringing_trunk);
 }
 
 static void sla_stop_ringing_station(struct sla_ringing_station *ringing_station,
@@ -6026,7 +6123,7 @@
 	}
 
 done:
-	ast_free(ringing_station);
+	sla_ringing_station_destroy(ringing_station);
 }
 
 static void sla_dial_state_callback(struct ast_dial *dial)
@@ -6078,8 +6175,10 @@
 			if (rm)
 				AST_LIST_REMOVE_CURRENT(entry);
 
-			if (trunk_ref)
+			if (trunk_ref) {
+				ao2_ref(s_trunk_ref, 1);
 				*trunk_ref = s_trunk_ref;
+			}
 
 			break;
 		}
@@ -6097,7 +6196,7 @@
 	struct sla_ringing_station *ringing_station;
 
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
-		struct sla_trunk_ref *s_trunk_ref = NULL;
+		RAII_VAR(struct sla_trunk_ref *, s_trunk_ref, NULL, ao2_cleanup);
 		struct sla_ringing_trunk *ringing_trunk = NULL;
 		struct run_station_args args;
 		enum ast_dial_result dial_res;
@@ -6130,7 +6229,7 @@
 				ast_dial_join(ringing_station->station->dial);
 				ast_dial_destroy(ringing_station->station->dial);
 				ringing_station->station->dial = NULL;
-				ast_free(ringing_station);
+				sla_ringing_station_destroy(ringing_station);
 				break;
 			}
 			/* Track the channel that answered this trunk */
@@ -6141,12 +6240,14 @@
 			/* Now, start a thread that will connect this station to the trunk.  The rest of
 			 * the code here sets up the thread and ensures that it is able to save the arguments
 			 * before they are no longer valid since they are allocated on the stack. */
+			ao2_ref(s_trunk_ref, 1);
 			args.trunk_ref = s_trunk_ref;
+			ao2_ref(ringing_station->station, 1);
 			args.station = ringing_station->station;
 			args.cond = &cond;
 			args.cond_lock = &cond_lock;
-			ast_free(ringing_trunk);
-			ast_free(ringing_station);
+			sla_ringing_trunk_destroy(ringing_trunk);
+			sla_ringing_station_destroy(ringing_station);
 			ast_mutex_init(&cond_lock);
 			ast_cond_init(&cond, NULL);
 			ast_mutex_lock(&cond_lock);
@@ -6200,7 +6301,7 @@
 			continue;
 		if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
 			AST_LIST_REMOVE_CURRENT(entry);
-			ast_free(failed_station);
+			sla_failed_station_destroy(failed_station);
 			break;
 		}
 		res = 1;
@@ -6253,11 +6354,9 @@
 	if (res != AST_DIAL_RESULT_TRYING) {
 		struct sla_failed_station *failed_station;
 		ast_dial_destroy(dial);
-		if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
-			return -1;
-		failed_station->station = station;
-		failed_station->last_try = ast_tvnow();
-		AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
+		if ((failed_station = sla_create_failed_station(station))) {
+			AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
+		}
 		return -1;
 	}
 	if (!(ringing_station = sla_create_ringing_station(station))) {
@@ -6296,6 +6395,8 @@
 		if (trunk_ref->trunk == trunk)
 			break;
 	}
+
+	ao2_ref(trunk_ref, 1);
 
 	return trunk_ref;
 }
@@ -6308,7 +6409,7 @@
 static int sla_check_station_delay(struct sla_station *station, 
 	struct sla_ringing_trunk *ringing_trunk)
 {
-	struct sla_trunk_ref *trunk_ref;
+	RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
 	unsigned int delay = UINT_MAX;
 	int time_left, time_elapsed;
 
@@ -6401,7 +6502,7 @@
 			ast_dial_join(ringing_station->station->dial);
 			ast_dial_destroy(ringing_station->station->dial);
 			ringing_station->station->dial = NULL;
-			ast_free(ringing_station);
+			sla_ringing_station_destroy(ringing_station);
 		}
 	}
 	AST_LIST_TRAVERSE_SAFE_END
@@ -6558,8 +6659,10 @@
 {
 	struct sla_station *station;
 	int res = 0;
-
-	AST_LIST_TRAVERSE(&sla_stations, station, entry) {
+	struct ao2_iterator i;
+
+	i = ao2_iterator_init(sla_stations, 0);
+	for (; (station = ao2_iterator_next(&i)); ao2_ref(station, -1)) {
 		struct sla_ringing_trunk *ringing_trunk;
 		int time_left;
 
@@ -6589,6 +6692,7 @@
 		if (time_left < *timeout)
 			*timeout = time_left;
 	}
+	ao2_iterator_destroy(&i);
 
 	return res;
 }
@@ -6630,47 +6734,19 @@
 	return 1;
 }
 
-static int sla_load_config(int reload);
-
-/*!
- * \internal
- * \brief Check if we can do a reload of SLA, and do it if we can
- * \pre sla.lock is locked.
- */
-static void sla_check_reload(void)
-{
-	struct sla_station *station;
-	struct sla_trunk *trunk;
-
-	if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks)
-		|| !AST_LIST_EMPTY(&sla.ringing_stations) || !AST_LIST_EMPTY(&sla.failed_stations)) {
-		return;
-	}
-
-	AST_RWLIST_RDLOCK(&sla_stations);
-	AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
-		if (station->ref_count)
-			break;
-	}
-	AST_RWLIST_UNLOCK(&sla_stations);
-	if (station) {
-		return;
-	}
-
-	AST_RWLIST_RDLOCK(&sla_trunks);
-	AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
-		if (trunk->ref_count || trunk->chan || trunk->active_stations || trunk->hold_stations) {
-			break;
-		}
-	}
-	AST_RWLIST_UNLOCK(&sla_trunks);
-	if (trunk) {
-		return;
-	}
-
-	/* yay */
-	sla_load_config(1);
-	sla.reload = 0;
+static void sla_event_destroy(struct sla_event *event)
+{
+	if (event->trunk_ref) {
+		ao2_ref(event->trunk_ref, -1);
+		event->trunk_ref = NULL;
+	}
+
+	if (event->station) {
+		ao2_ref(event->station, -1);
+		event->station = NULL;
+	}
+
+	ast_free(event);
 }
 
 static void *sla_thread(void *data)
@@ -6709,27 +6785,21 @@
 			case SLA_EVENT_RINGING_TRUNK:
 				sla_handle_ringing_trunk_event();
 				break;
-			case SLA_EVENT_RELOAD:
-				sla.reload = 1;
-			case SLA_EVENT_CHECK_RELOAD:
-				break;
-			}
-			ast_free(event);
+			}
+			sla_event_destroy(event);
 			ast_mutex_lock(&sla.lock);
 		}
-
-		if (sla.reload) {
-			sla_check_reload();
-		}
 	}
 
 	ast_mutex_unlock(&sla.lock);
 
-	while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
-		ast_free(ringing_station);
-
-	while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
-		ast_free(failed_station);
+	while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry))) {
+		sla_ringing_station_destroy(ringing_station);
+	}
+
+	while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry))) {
+		sla_failed_station_destroy(failed_station);
+	}
 
 	return NULL;
 }
@@ -6750,7 +6820,8 @@
 	char conf_name[MAX_CONFNUM];
 	struct ast_conference *conf;
 	struct ast_flags64 conf_flags = { 0 };
-	struct sla_trunk_ref *trunk_ref = args->trunk_ref;
+	RAII_VAR(struct sla_trunk_ref *, trunk_ref, args->trunk_ref, ao2_cleanup);
+	RAII_VAR(struct sla_station *, station, args->station, ao2_cleanup);
 	int caller_is_saved;
 	struct ast_party_caller caller;
 	int last_state = 0;
@@ -6822,8 +6893,8 @@
 			break;
 
 		/* check that SLA station that originated trunk call is still alive */
-		if (args->station && ast_device_state(args->station->device) == AST_DEVICE_NOT_INUSE) {
-			ast_debug(3, "Originating station device %s no longer active\n", args->station->device);
+		if (station && ast_device_state(station->device) == AST_DEVICE_NOT_INUSE) {
+			ast_debug(3, "Originating station device %s no longer active\n", station->device);
 			trunk_ref->trunk->chan = NULL;
 			break;
 		}
@@ -6876,15 +6947,19 @@
 	return NULL;
 }
 
-/*! \brief For a given station, choose the highest priority idle trunk
+/*!
+ * \brief For a given station, choose the highest priority idle trunk
+ * \pre sla_station is locked
  */
 static struct sla_trunk_ref *sla_choose_idle_trunk(const struct sla_station *station)
 {
 	struct sla_trunk_ref *trunk_ref = NULL;
 
 	AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
-		if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
+		if (trunk_ref->state == SLA_TRUNK_STATE_IDLE) {
+			ao2_ref(trunk_ref, 1);
 			break;
+		}
 	}
 
 	return trunk_ref;
@@ -6893,8 +6968,8 @@
 static int sla_station_exec(struct ast_channel *chan, const char *data)
 {
 	char *station_name, *trunk_name;
-	struct sla_station *station;
-	struct sla_trunk_ref *trunk_ref = NULL;
+	RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
+	RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
 	char conf_name[MAX_CONFNUM];
 	struct ast_flags64 conf_flags = { 0 };
 	struct ast_conference *conf;
@@ -6914,25 +6989,21 @@
 		return 0;
 	}
 
-	AST_RWLIST_WRLOCK(&sla_stations);
 	station = sla_find_station(station_name);
-	if (station)
-		ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
-	AST_RWLIST_UNLOCK(&sla_stations);
 
 	if (!station) {
 		ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
 		pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
-		sla_queue_event(SLA_EVENT_CHECK_RELOAD);
 		return 0;
 	}
 
-	AST_RWLIST_RDLOCK(&sla_trunks);
+	ao2_lock(station);
 	if (!ast_strlen_zero(trunk_name)) {
 		trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
-	} else
+	} else {
 		trunk_ref = sla_choose_idle_trunk(station);
-	AST_RWLIST_UNLOCK(&sla_trunks);
+	}
+	ao2_unlock(station);
 
 	if (!trunk_ref) {
 		if (ast_strlen_zero(trunk_name))
@@ -6942,8 +7013,6 @@
 				"'%s' due to access controls.\n", trunk_name);
 		}
 		pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
-		ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
-		sla_queue_event(SLA_EVENT_CHECK_RELOAD);
 		return 0;
 	}
 
@@ -6972,7 +7041,7 @@
 			answer_trunk_chan(ringing_trunk->trunk->chan);
 			sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
 
-			free(ringing_trunk);
+			sla_ringing_trunk_destroy(ringing_trunk);
 
 			/* Queue up reprocessing ringing trunks, and then ringing stations again */
 			sla_queue_event(SLA_EVENT_RINGING_TRUNK);
@@ -6992,6 +7061,8 @@
 			.cond_lock = &cond_lock,
 			.cond = &cond,
 		};
+		ao2_ref(trunk_ref, 1);
+		ao2_ref(station, 1);
 		sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
 		/* Create a thread to dial the trunk and dump it into the conference.
 		 * However, we want to wait until the trunk has been dialed and the
@@ -7011,8 +7082,6 @@
 			pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
 			sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
 			trunk_ref->chan = NULL;
-			ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
-			sla_queue_event(SLA_EVENT_CHECK_RELOAD);
 			return 0;
 		}
 	}
@@ -7045,19 +7114,28 @@
 	
 	pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
 
-	ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
-	sla_queue_event(SLA_EVENT_CHECK_RELOAD);
-
 	return 0;
 }
 
+static void sla_trunk_ref_destructor(void *obj)
+{
+	struct sla_trunk_ref *trunk_ref = obj;
+
+	if (trunk_ref->trunk) {
+		ao2_ref(trunk_ref->trunk, -1);
+		trunk_ref->trunk = NULL;
+	}
+}
+
 static struct sla_trunk_ref *create_trunk_ref(struct sla_trunk *trunk)
 {
 	struct sla_trunk_ref *trunk_ref;
 
-	if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
+	if (!(trunk_ref = ao2_alloc(sizeof(*trunk_ref), sla_trunk_ref_destructor))) {
 		return NULL;
-
+	}
+
+	ao2_ref(trunk, 1);
 	trunk_ref->trunk = trunk;
 
 	return trunk_ref;
@@ -7067,9 +7145,11 @@
 {
 	struct sla_ringing_trunk *ringing_trunk;
 
-	if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
+	if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk)))) {
 		return NULL;
-	
+	}
+
+	ao2_ref(trunk, 1);
 	ringing_trunk->trunk = trunk;
 	ringing_trunk->ring_begin = ast_tvnow();
 
@@ -7082,6 +7162,16 @@
 	sla_queue_event(SLA_EVENT_RINGING_TRUNK);
 
 	return ringing_trunk;
+}
+
+static void sla_ringing_trunk_destroy(struct sla_ringing_trunk *ringing_trunk)
+{
+	if (ringing_trunk->trunk) {
+		ao2_ref(ringing_trunk->trunk, -1);
+		ringing_trunk->trunk = NULL;
+	}
+
+	ast_free(ringing_trunk);
 }
 
 enum {
@@ -7102,7 +7192,7 @@
 	char conf_name[MAX_CONFNUM];
 	struct ast_conference *conf;
 	struct ast_flags64 conf_flags = { 0 };
-	struct sla_trunk *trunk;
+	RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
 	struct sla_ringing_trunk *ringing_trunk;
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(trunk_name);
@@ -7126,16 +7216,11 @@
 		}
 	}
 
-	AST_RWLIST_WRLOCK(&sla_trunks);
 	trunk = sla_find_trunk(args.trunk_name);
-	if (trunk)
-		ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
-	AST_RWLIST_UNLOCK(&sla_trunks);
 
 	if (!trunk) {
 		ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
 		pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
-		sla_queue_event(SLA_EVENT_CHECK_RELOAD);	
 		return 0;
 	}
 
@@ -7143,8 +7228,6 @@
 		ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
 			args.trunk_name);
 		pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
-		ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
-		sla_queue_event(SLA_EVENT_CHECK_RELOAD);	
 		return 0;
 	}
 
@@ -7152,8 +7235,6 @@
 
 	if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
 		pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
-		ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
-		sla_queue_event(SLA_EVENT_CHECK_RELOAD);	
 		return 0;
 	}
 
@@ -7161,8 +7242,6 @@
 	conf = build_conf(conf_name, "", "", 1, 1, 1, chan, NULL);
 	if (!conf) {
 		pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
-		ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
-		sla_queue_event(SLA_EVENT_CHECK_RELOAD);	
 		return 0;
 	}
 	ast_set_flag64(&conf_flags, 
@@ -7196,46 +7275,37 @@
 	AST_LIST_TRAVERSE_SAFE_END;
 	ast_mutex_unlock(&sla.lock);
 	if (ringing_trunk) {
-		ast_free(ringing_trunk);
+		sla_ringing_trunk_destroy(ringing_trunk);
 		pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
 		/* Queue reprocessing of ringing trunks to make stations stop ringing
 		 * that shouldn't be ringing after this trunk stopped. */
 		sla_queue_event(SLA_EVENT_RINGING_TRUNK);
 	}
 
-	ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
-	sla_queue_event(SLA_EVENT_CHECK_RELOAD);	
-
 	return 0;
 }
 
 static enum ast_device_state sla_state(const char *data)
 {
 	char *buf, *station_name, *trunk_name;
-	struct sla_station *station;
+	RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
 	struct sla_trunk_ref *trunk_ref;
 	enum ast_device_state res = AST_DEVICE_INVALID;
 
 	trunk_name = buf = ast_strdupa(data);
 	station_name = strsep(&trunk_name, "_");
 
-	AST_RWLIST_RDLOCK(&sla_stations);
-	AST_LIST_TRAVERSE(&sla_stations, station, entry) {
-		if (strcasecmp(station_name, station->name))
-			continue;
-		AST_RWLIST_RDLOCK(&sla_trunks);
+	station = sla_find_station(station_name);
+	if (station) {
+		ao2_lock(station);
 		AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
-			if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
+			if (!strcasecmp(trunk_name, trunk_ref->trunk->name)) {
+				res = sla_state_to_devstate(trunk_ref->state);
 				break;
-		}
-		if (!trunk_ref) {
-			AST_RWLIST_UNLOCK(&sla_trunks);
-			break;
-		}
-		res = sla_state_to_devstate(trunk_ref->state);
-		AST_RWLIST_UNLOCK(&sla_trunks);
-	}
-	AST_RWLIST_UNLOCK(&sla_stations);
+			}
+		}
+		ao2_unlock(station);
+	}
 
 	if (res == AST_DEVICE_INVALID) {
 		ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
@@ -7245,26 +7315,39 @@
 	return res;
 }
 
-static void destroy_trunk(struct sla_trunk *trunk)
-{
+static int sla_trunk_release_refs(void *obj, void *arg, int flags)
+{
+	struct sla_trunk *trunk = obj;
 	struct sla_station_ref *station_ref;
 
-	if (!ast_strlen_zero(trunk->autocontext))
-		ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
-
-	while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
-		ast_free(station_ref);
-
-	ast_string_field_free_memory(trunk);
-	ast_free(trunk);
-}
-
-static void destroy_station(struct sla_station *station)
-{
+	while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry))) {
+		ao2_ref(station_ref, -1);
+	}
+
+	return 0;
+}
+
+static int sla_station_release_refs(void *obj, void *arg, int flags)
+{
+	struct sla_station *station = obj;
 	struct sla_trunk_ref *trunk_ref;
 
+	while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry))) {
+		ao2_ref(trunk_ref, -1);
+	}
+
+	return 0;
+}
+
+static void sla_station_destructor(void *obj)
+{
+	struct sla_station *station = obj;
+
+	ast_debug(1, "sla_station destructor for '%s'\n", station->name);
+
 	if (!ast_strlen_zero(station->autocontext)) {
-		AST_RWLIST_RDLOCK(&sla_trunks);
+		struct sla_trunk_ref *trunk_ref;
+
 		AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
 			char exten[AST_MAX_EXTENSION];
 			char hint[AST_MAX_APP];
@@ -7275,31 +7358,43 @@
 			ast_context_remove_extension(station->autocontext, hint, 
 				PRIORITY_HINT, sla_registrar);
 		}
-		AST_RWLIST_UNLOCK(&sla_trunks);
-	}
-
-	while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
-		ast_free(trunk_ref);
+	}
+
+	sla_station_release_refs(station, NULL, 0);
 
 	ast_string_field_free_memory(station);
-	ast_free(station);
+}
+
+static int sla_trunk_hash(const void *obj, const int flags)
+{
+	const struct sla_trunk *trunk = obj;
+
+	return ast_str_case_hash(trunk->name);
+}
+
+static int sla_trunk_cmp(void *obj, void *arg, int flags)
+{
+	struct sla_trunk *trunk = obj, *trunk2 = arg;
+
+	return !strcasecmp(trunk->name, trunk2->name) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+static int sla_station_hash(const void *obj, const int flags)
+{
+	const struct sla_station *station = obj;
+
+	return ast_str_case_hash(station->name);
+}
+
+static int sla_station_cmp(void *obj, void *arg, int flags)
+{
+	struct sla_station *station = obj, *station2 = arg;
+
+	return !strcasecmp(station->name, station2->name) ? CMP_MATCH | CMP_STOP : 0;
 }
 
 static void sla_destroy(void)
 {
-	struct sla_trunk *trunk;
-	struct sla_station *station;
-
-	AST_RWLIST_WRLOCK(&sla_trunks);
-	while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
-		destroy_trunk(trunk);
-	AST_RWLIST_UNLOCK(&sla_trunks);
-
-	AST_RWLIST_WRLOCK(&sla_stations);
-	while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
-		destroy_station(station);
-	AST_RWLIST_UNLOCK(&sla_stations);
-
 	if (sla.thread != AST_PTHREADT_NULL) {
 		ast_mutex_lock(&sla.lock);
 		sla.stop = 1;
@@ -7313,6 +7408,15 @@
 
 	ast_mutex_destroy(&sla.lock);
 	ast_cond_destroy(&sla.cond);
+
+	ao2_callback(sla_trunks, 0, sla_trunk_release_refs, NULL);
+	ao2_callback(sla_stations, 0, sla_station_release_refs, NULL);
+
+	ao2_ref(sla_trunks, -1);
+	sla_trunks = NULL;
+
+	ao2_ref(sla_stations, -1);
+	sla_stations = NULL;
 }
 
 static int sla_check_device(const char *device)
@@ -7328,11 +7432,27 @@
 	return 0;
 }
 
+static void sla_trunk_destructor(void *obj)
+{
+	struct sla_trunk *trunk = obj;
+
+	ast_debug(1, "sla_trunk destructor for '%s'\n", trunk->name);
+
+	if (!ast_strlen_zero(trunk->autocontext)) {
+		ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
+	}
+
+	sla_trunk_release_refs(trunk, NULL, 0);
+
+	ast_string_field_free_memory(trunk);
+}
+
 static int sla_build_trunk(struct ast_config *cfg, const char *cat)
 {
-	struct sla_trunk *trunk;
+	RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
 	struct ast_variable *var;
 	const char *dev;
+	int existing_trunk = 0;
 
 	if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
 		ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
@@ -7340,16 +7460,25 @@
 	}
 
 	if (sla_check_device(dev)) {
-		ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
+		ast_log(LOG_ERROR, "SLA Trunk '%s' defined with invalid device '%s'!\n",
 			cat, dev);
 		return -1;
 	}
 
-	if (!(trunk = ast_calloc_with_stringfields(1, struct sla_trunk, 32))) {
+	if ((trunk = sla_find_trunk(cat))) {
+		trunk->mark = 0;
+		existing_trunk = 1;
+	} else if ((trunk = ao2_alloc(sizeof(*trunk), sla_trunk_destructor))) {
+		if (ast_string_field_init(trunk, 32)) {
+			return -1;
+		}
+		ast_string_field_set(trunk, name, cat);
+	} else {
 		return -1;
 	}
 
-	ast_string_field_set(trunk, name, cat);
+	ao2_lock(trunk);
+
 	ast_string_field_set(trunk, device, dev);
 
 	for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
@@ -7378,54 +7507,65 @@
 		}
 	}
 
+	ao2_unlock(trunk);
+
 	if (!ast_strlen_zero(trunk->autocontext)) {
 		struct ast_context *context;
 		context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
 		if (!context) {
 			ast_log(LOG_ERROR, "Failed to automatically find or create "
 				"context '%s' for SLA!\n", trunk->autocontext);
-			destroy_trunk(trunk);
 			return -1;
 		}
 		if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
 			NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
 			ast_log(LOG_ERROR, "Failed to automatically create extension "
 				"for trunk '%s'!\n", trunk->name);
-			destroy_trunk(trunk);
 			return -1;
 		}
 	}
 
-	AST_RWLIST_WRLOCK(&sla_trunks);
-	AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
-	AST_RWLIST_UNLOCK(&sla_trunks);
+	if (!existing_trunk) {
+		ao2_link(sla_trunks, trunk);
+	}
 
 	return 0;
 }
 
+/*!
+ * \internal
+ * \pre station is not locked
+ */
 static void sla_add_trunk_to_station(struct sla_station *station, struct ast_variable *var)
 {
-	struct sla_trunk *trunk;
-	struct sla_trunk_ref *trunk_ref;
+	RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
+	struct sla_trunk_ref *trunk_ref = NULL;
 	struct sla_station_ref *station_ref;
 	char *trunk_name, *options, *cur;
+	int existing_trunk_ref = 0;
+	int existing_station_ref = 0;
 
 	options = ast_strdupa(var->value);
 	trunk_name = strsep(&options, ",");
-	
-	AST_RWLIST_RDLOCK(&sla_trunks);
-	AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
-		if (!strcasecmp(trunk->name, trunk_name))
-			break;
-	}
-
-	AST_RWLIST_UNLOCK(&sla_trunks);
+
+	trunk = sla_find_trunk(trunk_name);
 	if (!trunk) {
 		ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
 		return;
 	}
-	if (!(trunk_ref = create_trunk_ref(trunk)))
+
+	AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
+		if (trunk_ref->trunk == trunk) {
+			trunk_ref->mark = 0;
+			existing_trunk_ref = 1;
+			break;
+		}
+	}
+
+	if (!trunk_ref && !(trunk_ref = create_trunk_ref(trunk))) {
 		return;
+	}
+
 	trunk_ref->state = SLA_TRUNK_STATE_IDLE;
 
 	while ((cur = strsep(&options, ","))) {
@@ -7449,41 +7589,73 @@
 		}
 	}
 
-	if (!(station_ref = sla_create_station_ref(station))) {
-		ast_free(trunk_ref);
+	AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
+		if (station_ref->station == station) {
+			station_ref->mark = 0;
+			existing_station_ref = 1;
+			break;
+		}
+	}
+
+	if (!station_ref && !(station_ref = sla_create_station_ref(station))) {
+		if (!existing_trunk_ref) {
+			ao2_ref(trunk_ref, -1);
+		} else {
+			trunk_ref->mark = 1;
+		}
 		return;
 	}
-	ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
-	AST_RWLIST_WRLOCK(&sla_trunks);
-	AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
-	AST_RWLIST_UNLOCK(&sla_trunks);
-	AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
+
+	if (!existing_station_ref) {
+		ao2_lock(trunk);
+		AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
+		ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
+		ao2_unlock(trunk);
+	}
+
+	if (!existing_trunk_ref) {
+		ao2_lock(station);
+		AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
+		ao2_unlock(station);
+	}
 }
 
 static int sla_build_station(struct ast_config *cfg, const char *cat)
 {
-	struct sla_station *station;
+	RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
 	struct ast_variable *var;
 	const char *dev;
+	int existing_station = 0;
 
 	if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
 		ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
 		return -1;
 	}
 
-	if (!(station = ast_calloc_with_stringfields(1, struct sla_station, 32))) {
+	if ((station = sla_find_station(cat))) {
+		station->mark = 0;
+		existing_station = 1;
+	} else if ((station = ao2_alloc(sizeof(*station), sla_station_destructor))) {
+		if (ast_string_field_init(station, 32)) {
+			return -1;
+		}
+		ast_string_field_set(station, name, cat);
+	} else {
 		return -1;
 	}
 
-	ast_string_field_set(station, name, cat);
+	ao2_lock(station);
+
 	ast_string_field_set(station, device, dev);
 
 	for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
-		if (!strcasecmp(var->name, "trunk"))
+		if (!strcasecmp(var->name, "trunk")) {
+			ao2_unlock(station);
 			sla_add_trunk_to_station(station, var);
-		else if (!strcasecmp(var->name, "autocontext"))
+			ao2_lock(station);
+		} else if (!strcasecmp(var->name, "autocontext")) {
 			ast_string_field_set(station, autocontext, var->value);
-		else if (!strcasecmp(var->name, "ringtimeout")) {
+		} else if (!strcasecmp(var->name, "ringtimeout")) {
 			if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
 				ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
 					var->value, station->name);
@@ -7511,6 +7683,8 @@
 		}
 	}
 
+	ao2_unlock(station);
+
 	if (!ast_strlen_zero(station->autocontext)) {

[... 774 lines stripped ...]



More information about the asterisk-commits mailing list