Index: main/pbx.c
===================================================================
--- main/pbx.c	(revision 176560)
+++ main/pbx.c	(working copy)
@@ -967,6 +967,15 @@
 static unsigned int hashtab_hash_priority(const void *obj);
 static unsigned int hashtab_hash_labels(const void *obj);
 static void __ast_internal_context_destroy( struct ast_context *con);
+static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
+	int priority, const char *label, const char *callerid,
+	const char *application, void *data, void (*datad)(void *), const char *registrar);
+static int add_pri_lockopt(struct ast_context *con, struct ast_exten *tmp,
+	struct ast_exten *el, struct ast_exten *e, int replace, int lockhints);
+static int ast_add_extension2_lockopt(struct ast_context *con,
+	int replace, const char *extension, int priority, const char *label, const char *callerid,
+	const char *application, void *data, void (*datad)(void *),
+	const char *registrar, int lockconts, int lockhints);
 
 /* a func for qsort to use to sort a char array */
 static int compare_char(const void *a, const void *b)
@@ -1150,6 +1159,7 @@
 }
 
 static struct ast_context *find_context_locked(const char *context);
+static struct ast_context *find_context(const char *context);
 int check_contexts(char *, int);
 
 int check_contexts(char *file, int line )
@@ -3960,20 +3970,18 @@
 	return ret;
 }
 
-/*! \brief Add hint to hint list, check initial extension state */
-static int ast_add_hint(struct ast_exten *e)
+
+/*! \brief Add hint to hint list, check initial extension state; the hints had better be WRLOCKED already! */
+static int ast_add_hint_nolock(struct ast_exten *e)
 {
 	struct ast_hint *hint;
 
 	if (!e)
 		return -1;
 
-	AST_RWLIST_WRLOCK(&hints);
-
 	/* Search if hint exists, do nothing */
 	AST_RWLIST_TRAVERSE(&hints, hint, list) {
 		if (hint->exten == e) {
-			AST_RWLIST_UNLOCK(&hints);
 			ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
 			return -1;
 		}
@@ -3982,7 +3990,6 @@
 	ast_debug(2, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
 
 	if (!(hint = ast_calloc(1, sizeof(*hint)))) {
-		AST_RWLIST_UNLOCK(&hints);
 		return -1;
 	}
 	/* Initialize and insert new item at the top */
@@ -3990,10 +3997,21 @@
 	hint->laststate = ast_extension_state2(e);
 	AST_RWLIST_INSERT_HEAD(&hints, hint, list);
 
-	AST_RWLIST_UNLOCK(&hints);
 	return 0;
 }
 
+/*! \brief Add hint to hint list, check initial extension state */
+static int ast_add_hint(struct ast_exten *e)
+{
+	int ret;
+
+	AST_RWLIST_WRLOCK(&hints);
+	ret = ast_add_hint_nolock(e);
+	AST_RWLIST_UNLOCK(&hints);
+	
+	return ret;
+}
+
 /*! \brief Change hint for an extension */
 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
 {
@@ -4558,6 +4576,22 @@
 
 /*!
  * \brief lookup for a context with a given name,
+ * \retval found context or NULL if not found.
+*/
+static struct ast_context *find_context(const char *context)
+{
+	struct ast_context *c = NULL;
+	struct fake_context item;
+
+	ast_copy_string(item.name, context, sizeof(item.name));
+
+	c = ast_hashtab_lookup(contexts_table,&item);
+
+	return c;
+}
+
+/*!
+ * \brief lookup for a context with a given name,
  * \retval with conlock held if found.
  * \retval NULL if not found.
 */
@@ -6526,13 +6560,13 @@
 	}
 	ast_hashtab_end_traversal(iter);
 	wrlock_ver = ast_wrlock_contexts_version();
-
+	
 	ast_unlock_contexts(); /* this feels real retarded, but you must do
 							  what you must do If this isn't done, the following 
 						      wrlock is a guraranteed deadlock */
 	ast_wrlock_contexts();
 	if (ast_wrlock_contexts_version() > wrlock_ver+1) {
-		ast_log(LOG_WARNING,"Something changed the contexts in the middle of merging contexts!\n");
+		ast_log(LOG_WARNING,"==================!!!!!!!!!!!!!!!Something changed the contexts in the middle of merging contexts!\n");
 	}
 	
 	AST_RWLIST_WRLOCK(&hints);
@@ -6573,7 +6607,7 @@
 		 * individual extension, because the pattern will no longer match first.
 		 */
 		if (exten && exten->exten[0] == '_') {
-			ast_add_extension(exten->parent->name, 0, this->exten, PRIORITY_HINT, NULL,
+			ast_add_extension_nolock(exten->parent->name, 0, this->exten, PRIORITY_HINT, NULL,
 				0, exten->app, ast_strdup(exten->data), ast_free_ptr, registrar);
 			/* rwlocks are not recursive locks */
 			exten = ast_hint_extension_nolock(NULL, this->context, this->exten);
@@ -7152,6 +7186,25 @@
 }
 
 /*
+ * ast_add_extension_nolock -- use only in situations where the conlock is already held
+ * ENOENT  - no existence of context
+ *
+ */
+static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
+	int priority, const char *label, const char *callerid,
+	const char *application, void *data, void (*datad)(void *), const char *registrar)
+{
+	int ret = -1;
+	struct ast_context *c = find_context(context);
+
+	if (c) {
+		ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid,
+			application, data, datad, registrar, 0, 0);
+	}
+	
+	return ret;
+}
+/*
  * EBUSY   - can't lock
  * ENOENT  - no existence of context
  *
@@ -7294,6 +7347,17 @@
 static int add_pri(struct ast_context *con, struct ast_exten *tmp,
 	struct ast_exten *el, struct ast_exten *e, int replace)
 {
+	return add_pri_lockopt(con, tmp, el, e, replace, 1);
+}
+
+/*! 
+ * \brief add the extension in the priority chain.
+ * \retval 0 on success.
+ * \retval -1 on failure.
+*/
+static int add_pri_lockopt(struct ast_context *con, struct ast_exten *tmp,
+	struct ast_exten *el, struct ast_exten *e, int replace, int lockhints)
+{
 	struct ast_exten *ep;
 	struct ast_exten *eh=e;
 
@@ -7428,8 +7492,13 @@
 			e->next = NULL;	/* e is no more at the head, so e->next must be reset */
 		}
 		/* And immediately return success. */
-		if (tmp->priority == PRIORITY_HINT)
-			 ast_add_hint(tmp);
+		if (tmp->priority == PRIORITY_HINT) {
+			if (lockhints) {
+				ast_add_hint(tmp);
+			} else {
+				ast_add_hint_nolock(tmp);
+			}
+		}
 	}
 	return 0;
 }
@@ -7464,6 +7533,19 @@
 	const char *application, void *data, void (*datad)(void *),
 	const char *registrar)
 {
+	return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid, application, data, datad, registrar, 1, 1);
+}
+
+/*! \brief
+ * Does all the work of ast_add_extension2, but adds two args, to determine if 
+ * context and hint locking should be done. In merge_and_delete, we need to do
+ * this without locking, as the locks are already held.
+ */
+static int ast_add_extension2_lockopt(struct ast_context *con,
+	int replace, const char *extension, int priority, const char *label, const char *callerid,
+	const char *application, void *data, void (*datad)(void *),
+	const char *registrar, int lockconts, int lockhints)
+{
 	/*
 	 * Sort extensions (or patterns) according to the rules indicated above.
 	 * These are implemented by the function ext_cmp()).
@@ -7536,7 +7618,9 @@
 	tmp->datad = datad;
 	tmp->registrar = registrar;
 
-	ast_wrlock_context(con);
+	if (lockconts) {
+		ast_wrlock_context(con);
+	}
 	
 	if (con->pattern_tree) { /* usually, on initial load, the pattern_tree isn't formed until the first find_exten; so if we are adding
 								an extension, and the trie exists, then we need to incrementally add this pattern to it. */
@@ -7569,7 +7653,9 @@
 	}
 	if (e && res == 0) { /* exact match, insert in the pri chain */
 		res = add_pri(con, tmp, el, e, replace);
-		ast_unlock_context(con);
+		if (lockconts) {
+			ast_unlock_context(con);
+		}
 		if (res < 0) {
 			errno = EEXIST;	/* XXX do we care ? */
 			return 0; /* XXX should we return -1 maybe ? */
@@ -7626,9 +7712,16 @@
 				
 		}
 		ast_hashtab_insert_safe(con->root_table, tmp);
-		ast_unlock_context(con);
-		if (tmp->priority == PRIORITY_HINT)
-			ast_add_hint(tmp);
+		if (lockconts) {
+			ast_unlock_context(con);
+		}
+		if (tmp->priority == PRIORITY_HINT) {
+			if (lockhints) {
+				ast_add_hint(tmp);
+			} else {
+				ast_add_hint_nolock(tmp);
+			}
+		}
 	}
 	if (option_debug) {
 		if (tmp->matchcid) {
