[svn-commits] rmudgett: branch rmudgett/parking r330571 - /team/rmudgett/parking/main/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Aug 1 18:07:37 CDT 2011


Author: rmudgett
Date: Mon Aug  1 18:07:27 2011
New Revision: 330571

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=330571
Log:
* Write remove dead parking dialplan items code.

* Move parking_con_dial to global since it is not configurable.

* Add features.conf reload lock to ensure reloading is not done
reentrantly.

Modified:
    team/rmudgett/parking/main/features.c

Modified: team/rmudgett/parking/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/parking/main/features.c?view=diff&rev=330571&r1=330570&r2=330571
==============================================================================
--- team/rmudgett/parking/main/features.c (original)
+++ team/rmudgett/parking/main/features.c Mon Aug  1 18:07:27 2011
@@ -456,8 +456,6 @@
 	char parkext[AST_MAX_EXTENSION];
 	/*! Context for which parking is made accessible */
 	char parking_con[AST_MAX_EXTENSION];
-	/*! Context for dialback for parking (KLUDGE) */
-	char parking_con_dial[AST_MAX_EXTENSION];
 	/*! First available extension for parking */
 	int parking_start;
 	/*! Last available extension for parking */
@@ -548,6 +546,19 @@
 static char pickupsound[256];                              /*!< Pickup sound */
 static char pickupfailsound[256];                          /*!< Pickup failure sound */
 
+/*!
+ * \brief Context for parking dialback to parker.
+ * \note The need for the context is a KLUDGE.
+ *
+ * \todo Might be able to eliminate the parking_con_dial context
+ * kludge by running app_dial directly in its own thread to
+ * simulate a PBX.
+ */
+static char parking_con_dial[] = "park-dial";
+
+/*! Ensure that features.conf reloads on one thread at a time. */
+AST_MUTEX_DEFINE_STATIC(features_reload_lock);
+
 static int adsipark;
 
 static int transferdigittimeout;
@@ -4319,10 +4330,11 @@
 				}
 
 /* BUGBUG need to check collision of recall call and parking pickup scenario. */
-/* BUGBUG need to protect cfg.parking_con_dial context from the config reload routine. */
-				con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->cfg.parking_con_dial, registrar);
+				con = ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar);
 				if (!con) {
-					ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->cfg.parking_con_dial);
+					ast_log(LOG_ERROR,
+						"Parking dial context '%s' does not exist and unable to create\n",
+						parking_con_dial);
 				} else {
 					char returnexten[AST_MAX_EXTENSION];
 					struct ast_datastore *features_datastore;
@@ -4354,7 +4366,7 @@
 					set_c_e_p(chan, pu->context, pu->exten, pu->priority);
 				} else {
 					if (comebacktoorigin) {
-						set_c_e_p(chan, pu->parkinglot->cfg.parking_con_dial, peername_flat, 1);
+						set_c_e_p(chan, parking_con_dial, peername_flat, 1);
 					} else {
 						snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
 						pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
@@ -4875,13 +4887,6 @@
 static void parkinglot_destroy(void *obj)
 {
 	struct ast_parkinglot *doomed = obj;
-	struct ast_context *con;
-
-/* BUGBUG cannot destroy context here since we don't know if it is in use by other parking lots. */
-	con = ast_context_find(doomed->cfg.parking_con);
-	if (con) {
-		ast_context_destroy(con, registrar);
-	}
 
 	/*
 	 * No need to destroy parked calls here because any parked call
@@ -4936,7 +4941,6 @@
 	.mohclass = "default",
 	.parkext = DEFAULT_PARK_EXTENSION,
 	.parking_con = "parkedcalls",
-	.parking_con_dial = "park-dial",
 	.parking_start = 701,
 	.parking_stop = 750,
 	.parkingtime = DEFAULT_PARK_TIME,
@@ -4945,7 +4949,6 @@
 /*! Default configuration for normal parking lots. */
 static const struct parkinglot_cfg parkinglot_cfg_default = {
 	.parkext = DEFAULT_PARK_EXTENSION,
-	.parking_con_dial = "park-dial",
 	.parkingtime = DEFAULT_PARK_TIME,
 };
 
@@ -5188,7 +5191,6 @@
 static int process_config(struct ast_config *cfg)
 {
 	int i;
-	struct ast_context *con = NULL;
 	struct ast_variable *var = NULL;
 	struct feature_group *fg = NULL;
 	char *ctg; 
@@ -5219,18 +5221,6 @@
 	atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
 
 	var = ast_variable_browse(cfg, "general");
-#if 1	// BUGBUG should not need this code after redesign
-	if (var) {
-		/* Find a general context in features.conf, we need to clear our existing default context */
-		/* Can't outright destroy the parking lot because it's needed in a little while. */
-		if ((con = ast_context_find(default_parkinglot->cfg.parking_con))) {
-			ast_context_destroy(con, registrar);
-		}
-		if ((con = ast_context_find(default_parkinglot->cfg.parking_con_dial))) {
-			ast_context_destroy(con, registrar);
-		}
-	} 
-#endif
 	build_parkinglot(DEFAULT_PARKINGLOT, var);
 
 	for (; var; var = var->next) {
@@ -5792,6 +5782,170 @@
 
 /*!
  * \internal
+ * \brief Remove unused parking lot access ramp items.
+ *
+ * \param con Dialplan database context.
+ * \param old_ramps Before configuration reload access ramp usage map.
+ * \param new_ramps After configuration reload access ramp usage map.
+ *
+ * \details
+ * Remove access ramp items that were in the old context but not in the
+ * new context.
+ *
+ * \return Nothing
+ */
+static void remove_dead_ramp_usage(struct ast_context *con, struct parking_dp_ramp_map *old_ramps, struct parking_dp_ramp_map *new_ramps)
+{
+	struct parking_dp_ramp *old_ramp;
+	struct parking_dp_ramp *new_ramp;
+	int cmp;
+
+	old_ramp = AST_LIST_FIRST(old_ramps);
+	new_ramp = AST_LIST_FIRST(new_ramps);
+
+	while (new_ramp) {
+		if (!old_ramp) {
+			/* No old ramps left, so no dead ramps can remain. */
+			return;
+		}
+		cmp = strcmp(old_ramp->exten, new_ramp->exten);
+		if (cmp < 0) {
+			/* New map does not have old ramp. */
+			ast_context_remove_extension2(con, old_ramp->exten, 0, registrar, 0);
+			old_ramp = AST_LIST_NEXT(old_ramp, node);
+			continue;
+		}
+		if (cmp == 0) {
+			/* Old and new map have this ramp. */
+			old_ramp = AST_LIST_NEXT(old_ramp, node);
+		} else {
+			/* Old map does not have new ramp. */
+		}
+		new_ramp = AST_LIST_NEXT(new_ramp, node);
+	}
+
+	/* Any old ramps left must be dead. */
+	for (; old_ramp; old_ramp = AST_LIST_NEXT(old_ramp, node)) {
+		ast_context_remove_extension2(con, old_ramp->exten, 0, registrar, 0);
+	}
+}
+
+/*!
+ * \internal
+ * \brief Destroy the given parking space.
+ *
+ * \param con Dialplan database context.
+ * \param space Parking space.
+ *
+ * \return Nothing
+ */
+static void destroy_space(struct ast_context *con, int space)
+{
+	char exten[AST_MAX_EXTENSION];
+
+	/* Destroy all priorities of the parking space that we registered. */
+	snprintf(exten, sizeof(exten), "%d", space);
+	ast_context_remove_extension2(con, exten, 0, registrar, 0);
+}
+
+/*!
+ * \internal
+ * \brief Remove unused parking lot space items.
+ *
+ * \param con Dialplan database context.
+ * \param old_spaces Before configuration reload parking space usage map.
+ * \param new_spaces After configuration reload parking space usage map.
+ * \param destroy_space Function to destroy parking space item.
+ *
+ * \details
+ * Remove parking space items that were in the old context but
+ * not in the new context.
+ *
+ * \return Nothing
+ */
+static void remove_dead_spaces_usage(struct ast_context *con,
+	struct parking_dp_space_map *old_spaces, struct parking_dp_space_map *new_spaces,
+	void (*destroy_space)(struct ast_context *con, int space))
+{
+	struct parking_dp_spaces *old_range;
+	struct parking_dp_spaces *new_range;
+	int space;/*!< Current position in the current old range. */
+	int stop;
+
+	old_range = AST_LIST_FIRST(old_spaces);
+	new_range = AST_LIST_FIRST(new_spaces);
+	space = -1;
+
+	while (old_range) {
+		if (space < old_range->start) {
+			space = old_range->start;
+		}
+		if (new_range) {
+			if (space < new_range->start) {
+				/* Current position in old range starts before new range. */
+				if (old_range->stop < new_range->start) {
+					/* Old range ends before new range. */
+					stop = old_range->stop;
+					old_range = AST_LIST_NEXT(old_range, node);
+				} else {
+					/* Tail of old range overlaps new range. */
+					stop = new_range->start - 1;
+				}
+			} else if (/* new_range->start <= space && */ space <= new_range->stop) {
+				/* Current position in old range overlaps new range. */
+				if (old_range->stop <= new_range->stop) {
+					/* Old range ends at or before new range. */
+					old_range = AST_LIST_NEXT(old_range, node);
+				} else {
+					/* Old range extends beyond end of new range. */
+					space = new_range->stop + 1;
+					new_range = AST_LIST_NEXT(new_range, node);
+				}
+				continue;
+			} else /* if (new_range->stop < space) */ {
+				/* Current position in old range starts after new range. */
+				new_range = AST_LIST_NEXT(new_range, node);
+				continue;
+			}
+		} else {
+			/* No more new ranges.  All remaining old spaces are dead. */
+			stop = old_range->stop;
+			old_range = AST_LIST_NEXT(old_range, node);
+		}
+
+		/* Destroy dead parking spaces. */
+		for (; space <= stop; ++space) {
+			destroy_space(con, space);
+		}
+	}
+}
+
+/*!
+ * \internal
+ * \brief Remove unused parking lot context items.
+ *
+ * \param con Dialplan database context.
+ * \param old_ctx Before configuration reload context usage map.
+ * \param new_ctx After configuration reload context usage map.
+ *
+ * \details
+ * Remove context usage items that were in the old context but not in the
+ * new context.
+ *
+ * \return Nothing
+ */
+static void remove_dead_context_usage(struct ast_context *con, struct parking_dp_context *old_ctx, struct parking_dp_context *new_ctx)
+{
+	remove_dead_ramp_usage(con, &old_ctx->access_extens, &new_ctx->access_extens);
+	remove_dead_spaces_usage(con, &old_ctx->spaces, &new_ctx->spaces, destroy_space);
+#if 0
+	/* I don't think we should destroy hints if the parking space still exists. */
+	remove_dead_spaces_usage(con, &old_ctx->hints, &new_ctx->hints, destroy_space_hint);
+#endif
+}
+
+/*!
+ * \internal
  * \brief Remove unused parking lot dialplan items.
  *
  * \param old_map Before configuration reload dialplan usage map.
@@ -5805,7 +5959,55 @@
  */
 static void remove_dead_dialplan_useage(struct parking_dp_map *old_map, struct parking_dp_map *new_map)
 {
-	/*! \todo BUGBUG remove_dead_dialplan_useage() not written */
+	struct parking_dp_context *old_ctx;
+	struct parking_dp_context *new_ctx;
+	struct ast_context *con;
+	int cmp;
+
+	old_ctx = AST_LIST_FIRST(old_map);
+	new_ctx = AST_LIST_FIRST(new_map);
+
+	while (new_ctx) {
+		if (!old_ctx) {
+			/* No old contexts left, so no dead stuff can remain. */
+			return;
+		}
+		cmp = strcmp(old_ctx->context, new_ctx->context);
+		if (cmp < 0) {
+			/* New map does not have old map context. */
+			ast_wrlock_contexts();
+			con = ast_context_find(old_ctx->context);
+			if (con) {
+				ast_context_destroy(con, registrar);
+			}
+			ast_unlock_contexts();
+			old_ctx = AST_LIST_NEXT(old_ctx, node);
+			continue;
+		}
+		if (cmp == 0) {
+			/* Old and new map have this context. */
+			ast_wrlock_contexts();
+			con = ast_context_find(old_ctx->context);
+			if (con) {
+				remove_dead_context_usage(con, old_ctx, new_ctx);
+			}
+			ast_unlock_contexts();
+			old_ctx = AST_LIST_NEXT(old_ctx, node);
+		} else {
+			/* Old map does not have new map context. */
+		}
+		new_ctx = AST_LIST_NEXT(new_ctx, node);
+	}
+
+	/* Any old contexts left must be dead. */
+	for (; old_ctx; old_ctx = AST_LIST_NEXT(old_ctx, node)) {
+		ast_wrlock_contexts();
+		con = ast_context_find(old_ctx->context);
+		if (con) {
+			ast_context_destroy(con, registrar);
+		}
+		ast_unlock_contexts();
+	}
 }
 
 static int parkinglot_markall_cb(void *obj, void *arg, int flags)
@@ -6001,9 +6203,28 @@
 
 int ast_features_reload(void)
 {
-/* BUGBUG Should always destroy cfg.parking_con_dial context and protect it from the manage_parkinglot() thread. */
-/* Destroying it removes buildup of recalled extensions in the context. */
-	return load_config(1);
+	struct ast_context *con;
+	int res;
+
+	ast_mutex_lock(&features_reload_lock);/* Searialize reloading features.conf */
+
+	/*
+	 * Always destroy the parking_con_dial context to remove buildup
+	 * of recalled extensions in the context.  At worst, the parked
+	 * call gets hungup attempting to run an invalid extension when
+	 * we are trying to callback the parker or the preset return
+	 * extension.  This is a small window of opportunity on an
+	 * execution chain that is not expected to happen very often.
+	 */
+	con = ast_context_find(parking_con_dial);
+	if (con) {
+		ast_context_destroy(con, registrar);
+	}
+
+	res = load_config(1);
+	ast_mutex_unlock(&features_reload_lock);
+
+	return res;
 }
 
 static char *handle_features_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)




More information about the svn-commits mailing list