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)
}
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 )
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;
}
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 */
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)
{
}
}
+/*!
+ * \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.
}
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);
* 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);
return 0;
}
+/*
+ * 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
*/
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;
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;
}
int replace, const char *extension, int priority, const char *label, const char *callerid,
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.
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. */
}
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 ? */
}
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) {