[asterisk-commits] rmudgett: branch rmudgett/parking r330571 - /team/rmudgett/parking/main/
SVN commits to the Asterisk project
asterisk-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 asterisk-commits
mailing list