[asterisk-commits] russell: branch russell/indications r174539 - in /team/russell/indications: i...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Feb 10 07:54:46 CST 2009


Author: russell
Date: Tue Feb 10 07:54:46 2009
New Revision: 174539

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=174539
Log:
knock off a couple todo items

Modified:
    team/russell/indications/include/asterisk/indications.h
    team/russell/indications/main/indications.c

Modified: team/russell/indications/include/asterisk/indications.h
URL: http://svn.digium.com/svn-view/asterisk/team/russell/indications/include/asterisk/indications.h?view=diff&rev=174539&r1=174538&r2=174539
==============================================================================
--- team/russell/indications/include/asterisk/indications.h (original)
+++ team/russell/indications/include/asterisk/indications.h Tue Feb 10 07:54:46 2009
@@ -41,6 +41,12 @@
 	const char *name;   /*!< Identifying name */
 	const char *data;   /*!< Actual zone description */
 	AST_LIST_ENTRY(ast_tone_zone_sound) entry;
+	union {
+		uint32_t __padding;
+		struct {
+			unsigned int killme:1;
+		};
+	};
 };
 
 struct ast_tone_zone {
@@ -49,6 +55,12 @@
 	int  nrringcadence;      /*!< # registered ringcadence elements */
 	int *ringcadence;        /*!< Ring cadence */
 	AST_LIST_HEAD_NOLOCK(, ast_tone_zone_sound) tones;		/*!< The known tones for this zone */
+	union {
+		uint32_t __padding;
+		struct {
+			unsigned int killme:1;
+		};
+	};
 };
 
 /*!

Modified: team/russell/indications/main/indications.c
URL: http://svn.digium.com/svn-view/asterisk/team/russell/indications/main/indications.c?view=diff&rev=174539&r1=174538&r2=174539
==============================================================================
--- team/russell/indications/main/indications.c (original)
+++ team/russell/indications/main/indications.c Tue Feb 10 07:54:46 2009
@@ -26,8 +26,6 @@
 /*
  * XXX TODO
  *  - API documentation
- *  - finish re-write of config parsing
- *  - re-use an object for a country if it already exists when loading config
  *  - fix users of the API to account for ref count (only chan_unistim left)
  *  - Integrate work to pull out tone parsing into an API
  *  - change the code such that tone definitions are only parsed once
@@ -853,21 +851,30 @@
 static int handle_stopplaytones(struct ast_channel *chan, void *data)
 {
 	ast_playtones_stop(chan);
+
 	return 0;
 }
 
 static int is_valid_tone_zone(struct ast_tone_zone *zone)
 {
-	return (!ast_strlen_zero(zone->description) && !AST_LIST_EMPTY(&zone->tones));
-}
-
+	int res;
+
+	ast_tone_zone_lock(zone);
+	res = (!ast_strlen_zero(zone->description) && !AST_LIST_EMPTY(&zone->tones));
+	ast_tone_zone_unlock(zone);
+
+	return res;
+}
+
+/*!
+ * \note This is called with the tone zone locked.
+ */
 static void store_tone_zone_ring_cadence(struct ast_tone_zone *zone, const char *val)
 {
-	char *ring, *c;
 	char buf[1024];
+	char *ring, *c = buf;
 
 	ast_copy_string(buf, val, sizeof(buf));
-	c = buf;
 
 	while ((ring = strsep(&c, ","))) {
 		int *tmp, val;
@@ -889,25 +896,23 @@
 	}
 }
 
+/*!
+ * \note This is called with the tone zone locked.
+ */
 static void store_tone_zone_sound(struct ast_tone_zone *zone, const char *name,
 		const char *val)
 {
 	struct ast_tone_zone_sound *ts;
-	int ignore = 0;
-
-	/* add tone to country */
-	AST_LIST_TRAVERSE(&zone->tones, ts, entry) {
+
+	/* Remove the tone if it already existed, we'll redo it with new values */
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&zone->tones, ts, entry) {
 		if (!strcasecmp(name, ts->name)) {
-			/* already there */
-			ast_log(LOG_NOTICE, "Duplicate entry '%s' skipped.\n", name);
-			ignore = 1;
+			AST_LIST_REMOVE_CURRENT(entry);
+			ast_tone_zone_sound_destroy(ts);
 			break;
 		}
 	}
-
-	if (ignore) {
-		return;
-	}
+	AST_LIST_TRAVERSE_SAFE_END
 
 	/* not there, add it to the back */
 	if (!(ts = ast_calloc(1, sizeof(*ts)))) {
@@ -941,31 +946,105 @@
 	CV_END;
 }
 
+static void reset_tone_zone(struct ast_tone_zone *zone)
+{
+	ast_tone_zone_lock(zone);
+
+	zone->killme = 0;
+
+	if (zone->nrringcadence) {
+		zone->nrringcadence = 0;
+		ast_free(zone->ringcadence);
+		zone->ringcadence = NULL;
+	}
+
+	ast_tone_zone_unlock(zone);
+}
+
 static int parse_tone_zone(struct ast_config *cfg, const char *country)
 {
 	struct ast_variable *v;
 	struct ast_tone_zone *zone;
-
-	if (!(zone = ast_tone_zone_alloc())) {
+	struct ast_tone_zone tmp_zone = {
+		.nrringcadence = 0,
+	};
+	int allocd = 0;
+
+	ast_copy_string(tmp_zone.country, country, sizeof(tmp_zone.country));
+
+	if ((zone = ao2_find(ast_tone_zones, &tmp_zone, OBJ_POINTER))) {
+		reset_tone_zone(zone);
+	} else if ((zone = ast_tone_zone_alloc())) {
+		allocd = 1;
+		ast_copy_string(zone->country, country, sizeof(zone->country));
+	} else {
 		return -1;
 	}
 
-	ast_copy_string(zone->country, country, sizeof(zone->country));
-
+	ast_tone_zone_lock(zone);
 	for (v = ast_variable_browse(cfg, country); v; v = v->next) {
 		store_config_tone_zone(zone, v->name, v->value);
 	}
-
-	if (is_valid_tone_zone(zone)) {
-		if (ast_register_indication_country(zone)) {
-			ast_log(LOG_WARNING, "Unable to register indication at line %d.\n",v->lineno);
-			zone = ast_tone_zone_unref(zone);
-		}
-	} else {
-		zone = ast_tone_zone_unref(zone);
-	}
+	ast_tone_zone_unlock(zone);
+
+	if (allocd) { 
+		if (!is_valid_tone_zone(zone)) {
+			ast_log(LOG_WARNING, "Indication country '%s' is invalid\n", country);
+		} else if (ast_register_indication_country(zone)) {
+			ast_log(LOG_WARNING, "Unable to register indication country '%s'.\n", 
+					country);
+		}
+	}
+
+	zone = ast_tone_zone_unref(zone);
 
 	return 0;
+}
+
+/*!
+ * Mark the zone and its tones before parsing configuration.  We will use this
+ * to know what to remove after configuration is parsed.
+ */
+static int tone_zone_mark(void *obj, void *arg, int flags)
+{
+	struct ast_tone_zone *zone = obj;
+	struct ast_tone_zone_sound *s;
+
+	ast_tone_zone_lock(zone);
+
+	zone->killme = 1;
+
+	AST_LIST_TRAVERSE(&zone->tones, s, entry) {
+		s->killme = 1;
+	}
+
+	ast_tone_zone_unlock(zone);
+
+	return 0;
+}
+
+/*!
+ * Prune tones no longer in the configuration, and have the tone zone unlinked
+ * if it is no longer in the configuration at all.
+ */
+static int prune_tone_zone(void *obj, void *arg, int flags)
+{
+	struct ast_tone_zone *zone = obj;
+	struct ast_tone_zone_sound *s;
+
+	ast_tone_zone_lock(zone);
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&zone->tones, s, entry) {
+		if (s->killme) {
+			AST_LIST_REMOVE_CURRENT(entry);
+			ast_tone_zone_sound_destroy(s);
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END
+
+	ast_tone_zone_unlock(zone);
+
+	return zone->killme ? CMP_MATCH : 0;
 }
 
 /*! \brief load indications module */
@@ -975,6 +1054,7 @@
 	const char *cxt = NULL;
 	const char *country = NULL;
 	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+	int res = -1;
 
 	cfg = ast_config_load2(config, NULL, config_flags);
 
@@ -984,10 +1064,10 @@
 		return 0;
 	}
 
-	if (reload) {
-		/* Clear indications */
-		ast_unregister_indication_country(NULL);
-	}
+	/* Lock the container to prevent multiple simultaneous reloads */
+	ao2_lock(ast_tone_zones);
+
+	ao2_callback(ast_tone_zones, OBJ_NODATA, tone_zone_mark, NULL);
 
 	/* Use existing config to populate the Indication table */
 	while ((cxt = ast_category_browse(cfg, cxt))) {
@@ -997,10 +1077,12 @@
 		}
 
 		if (parse_tone_zone(cfg, cxt)) {
-			ast_config_destroy(cfg);
-			return -1;
-		}
-	}
+			goto return_cleanup;
+		}
+	}
+
+	ao2_callback(ast_tone_zones, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, 
+			prune_tone_zone, NULL);
 
 	/* determine which country is the default */
 	country = ast_variable_retrieve(cfg, "general", "country");
@@ -1008,9 +1090,13 @@
 		ast_log(LOG_WARNING, "Unable to set the default country (for indication tones)\n");
 	}
 
+	res = 0;
+
+return_cleanup:
+	ao2_unlock(ast_tone_zones);
 	ast_config_destroy(cfg);
 
-	return 0;
+	return res;
 }
 
 /*! \brief CLI entries for commands provided by this module */




More information about the asterisk-commits mailing list