Convert the PBX core to use read/write locks. This yields a nifty performance improve...
[asterisk/asterisk.git] / main / pbx.c
index 480c41a..f129667 100644 (file)
@@ -104,6 +104,7 @@ AST_APP_OPTIONS(waitexten_opts, {
 });
 
 struct ast_context;
+struct ast_app;
 
 /*!
    \brief ast_exten: An extension
@@ -119,6 +120,7 @@ struct ast_exten {
        const char *label;              /*!< Label */
        struct ast_context *parent;     /*!< The context this extension belongs to  */
        const char *app;                /*!< Application to execute */
+       struct ast_app *cached_app;     /*!< Cached location of application */
        void *data;                     /*!< Data to use (arguments) */
        void (*datad)(void *);          /*!< Data destructor */
        struct ast_exten *peer;         /*!< Next higher priority with our extension */
@@ -158,7 +160,7 @@ struct ast_ignorepat {
 
 /*! \brief ast_context: An extension context */
 struct ast_context {
-       ast_mutex_t lock;                       /*!< A lock to prevent multiple threads from clobbering the context */
+       ast_rwlock_t lock;                      /*!< A lock to prevent multiple threads from clobbering the context */
        struct ast_exten *root;                 /*!< The root of the list of extensions */
        struct ast_context *next;               /*!< Link them together */
        struct ast_include *includes;           /*!< Include other contexts */
@@ -175,7 +177,7 @@ struct ast_app {
        int (*execute)(struct ast_channel *chan, void *data);
        const char *synopsis;                   /*!< Synopsis text for 'show applications' */
        const char *description;                /*!< Description (help text) for 'show application &lt;name&gt;' */
-       AST_LIST_ENTRY(ast_app) list;           /*!< Next app in list */
+       AST_RWLIST_ENTRY(ast_app) list;         /*!< Next app in list */
        struct module *module;                  /*!< Module this app belongs to */
        char name[0];                           /*!< Name of the application */
 };
@@ -191,12 +193,14 @@ struct ast_state_cb {
 /*! \brief Structure for dial plan hints
 
   \note Hints are pointers from an extension in the dialplan to one or
-  more devices (tech/name) */
+  more devices (tech/name) 
+       - See \ref AstExtState
+*/
 struct ast_hint {
        struct ast_exten *exten;        /*!< Extension */
        int laststate;                  /*!< Last known state */
        struct ast_state_cb *callbacks; /*!< Callback list for this extension */
-       AST_LIST_ENTRY(ast_hint) list;  /*!< Pointer to next hint in list */
+       AST_RWLIST_ENTRY(ast_hint) list;/*!< Pointer to next hint in list */
 };
 
 static const struct cfextension_states {
@@ -236,15 +240,15 @@ static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
 int pbx_builtin_setvar(struct ast_channel *, void *);
 static int pbx_builtin_importvar(struct ast_channel *, void *);
 
-AST_MUTEX_DEFINE_STATIC(globalslock);
+AST_RWLOCK_DEFINE_STATIC(globalslock);
 static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
 
 static int autofallthrough = 1;
 
 AST_MUTEX_DEFINE_STATIC(maxcalllock);
-static int countcalls = 0;
+static int countcalls;
 
-static AST_LIST_HEAD_STATIC(acf_root, ast_custom_function);
+static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
 
 /*! \brief Declaration of builtin applications */
 static struct pbx_builtin {
@@ -261,7 +265,8 @@ static struct pbx_builtin {
        "Answer a channel if ringing",
        "  Answer([delay]): If the call has not been answered, this application will\n"
        "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
-       "Asterisk will wait this number of milliseconds before answering the call.\n"
+       "Asterisk will wait this number of milliseconds before returning to\n"
+       "the dialplan after answering the call.\n"
        },
 
        { "BackGround", pbx_builtin_background,
@@ -318,8 +323,13 @@ static struct pbx_builtin {
        "calling channel to continue dialplan execution at the specified priority.\n"
        "If no specific extension, or extension and context, are specified, then this\n"
        "application will jump to the specified priority of the current extension.\n"
+       "  At least a priority is required as an argument, or the goto will return a -1,\n"
+       "and the channel and call will be terminated.\n"
        "  If the attempt to jump to another location in the dialplan is not successful,\n"
-       "then the channel will continue at the next priority of the current extension.\n"
+       "then the execution engine will try to find and execute the code in the 'i' (invalid)\n"
+       "extension in the current context. If that does not exist, it will try to execute the\n"
+       "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
+       "channel is hung up, and the execution of instructions on the channel is terminated.\n"
        },
 
        { "GotoIf", pbx_builtin_gotoif,
@@ -330,7 +340,12 @@ static struct pbx_builtin {
        "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
        "false. The labels are specified with the same syntax as used within the Goto\n"
        "application.  If the label chosen by the condition is omitted, no jump is\n"
-       "performed, but execution continues with the next priority in the dialplan.\n"
+       "performed, and the execution passes to the next instruction.\n"
+       "If the target location is bogus, and does not exist, the execution engine will try \n"
+       "to find and execute the code in the 'i' (invalid)\n"
+       "extension in the current context. If that does not exist, it will try to execute the\n"
+       "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
+       "channel is hung up, and the execution of instructions on the channel is terminated.\n"
        },
 
        { "GotoIfTime", pbx_builtin_gotoiftime,
@@ -338,6 +353,7 @@ static struct pbx_builtin {
        "  GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
        "This application will have the calling channel jump to the specified location\n"
        "in the dialplan if the current time matches the given time specification.\n"
+       "If the target jump location is bogus, the same actions would be taken as for Goto.\n"
        },
 
        { "ImportVar", pbx_builtin_importvar,
@@ -456,12 +472,12 @@ static struct pbx_builtin {
 
 };
 
-static struct ast_context *contexts = NULL;
-AST_MUTEX_DEFINE_STATIC(conlock);              /*!< Lock for the ast_context list */
+static struct ast_context *contexts;
+AST_RWLOCK_DEFINE_STATIC(conlock);             /*!< Lock for the ast_context list */
 
-static AST_LIST_HEAD_STATIC(apps, ast_app);
+static AST_RWLIST_HEAD_STATIC(apps, ast_app);
 
-static AST_LIST_HEAD_STATIC(switches, ast_switch);
+static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
 
 static int stateid = 1;
 /* WARNING:
@@ -470,15 +486,15 @@ static int stateid = 1;
    function will take the locks in conlock/hints order, so any other
    paths that require both locks must also take them in that order.
 */
-static AST_LIST_HEAD_STATIC(hints, ast_hint);
-struct ast_state_cb *statecbs = NULL;
+static AST_RWLIST_HEAD_STATIC(hints, ast_hint);
+struct ast_state_cb *statecbs;
 
 /*
    \note This function is special. It saves the stack so that no matter
    how many times it is called, it returns to the same place */
 int pbx_exec(struct ast_channel *c,            /*!< Channel */
-               struct ast_app *app,            /*!< Application */
-               void *data)                     /*!< Data for execution */
+            struct ast_app *app,               /*!< Application */
+            void *data)                        /*!< Data for execution */
 {
        int res;
 
@@ -518,12 +534,12 @@ struct ast_app *pbx_findapp(const char *app)
 {
        struct ast_app *tmp;
 
-       AST_LIST_LOCK(&apps);
-       AST_LIST_TRAVERSE(&apps, tmp, list) {
+       AST_RWLIST_RDLOCK(&apps);
+       AST_RWLIST_TRAVERSE(&apps, tmp, list) {
                if (!strcasecmp(tmp->name, app))
                        break;
        }
-       AST_LIST_UNLOCK(&apps);
+       AST_RWLIST_UNLOCK(&apps);
 
        return tmp;
 }
@@ -532,12 +548,12 @@ static struct ast_switch *pbx_findswitch(const char *sw)
 {
        struct ast_switch *asw;
 
-       AST_LIST_LOCK(&switches);
-       AST_LIST_TRAVERSE(&switches, asw, list) {
+       AST_RWLIST_RDLOCK(&switches);
+       AST_RWLIST_TRAVERSE(&switches, asw, list) {
                if (!strcasecmp(asw->name, sw))
                        break;
        }
-       AST_LIST_UNLOCK(&switches);
+       AST_RWLIST_UNLOCK(&switches);
 
        return asw;
 }
@@ -859,12 +875,12 @@ int ast_extension_close(const char *pattern, const char *data, int needmore)
 struct ast_context *ast_context_find(const char *name)
 {
        struct ast_context *tmp = NULL;
-       ast_mutex_lock(&conlock);
+       ast_rdlock_contexts();
        while ( (tmp = ast_walk_contexts(tmp)) ) {
                if (!name || !strcasecmp(name, tmp->name))
                        break;
        }
-       ast_mutex_unlock(&conlock);
+       ast_unlock_contexts();
        return tmp;
 }
 
@@ -1092,9 +1108,12 @@ static char *substring(const char *value, int offset, int length, char *workspac
        return ret;
 }
 
-/*! \brief  pbx_retrieve_variable: Support for Asterisk built-in variables and
-      functions in the dialplan
-  ---*/
+/*! \brief  Support for Asterisk built-in variables in the dialplan
+
+\note  See also
+       - \ref AstVar   Channel variables
+       - \ref AstCauses The HANGUPCAUSE variable
+ */
 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
 {
        const char not_found = '\0';
@@ -1183,7 +1202,7 @@ void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, c
                if (!places[i])
                        continue;
                if (places[i] == &globals)
-                       ast_mutex_lock(&globalslock);
+                       ast_rwlock_rdlock(&globalslock);
                AST_LIST_TRAVERSE(places[i], variables, entries) {
                        if (strcasecmp(ast_var_name(variables), var)==0) {
                                s = ast_var_value(variables);
@@ -1191,7 +1210,7 @@ void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, c
                        }
                }
                if (places[i] == &globals)
-                       ast_mutex_unlock(&globalslock);
+                       ast_rwlock_unlock(&globalslock);
        }
        if (s == &not_found || s == NULL)
                *ret = NULL;
@@ -1218,14 +1237,14 @@ static int handle_show_functions(int fd, int argc, char *argv[])
 
        ast_cli(fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
 
-       AST_LIST_LOCK(&acf_root);
-       AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
+       AST_RWLIST_RDLOCK(&acf_root);
+       AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
                if (!like || strstr(acf->name, argv[4])) {
                        count_acf++;
                        ast_cli(fd, "%-20.20s  %-35.35s  %s\n", acf->name, acf->syntax, acf->synopsis);
                }
        }
-       AST_LIST_UNLOCK(&acf_root);
+       AST_RWLIST_UNLOCK(&acf_root);
 
        ast_cli(fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
 
@@ -1296,14 +1315,14 @@ static char *complete_show_function(const char *line, const char *word, int pos,
        int wordlen = strlen(word);
 
        /* case-insensitive for convenience in this 'complete' function */
-       AST_LIST_LOCK(&acf_root);
-       AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
+       AST_RWLIST_RDLOCK(&acf_root);
+       AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
                if (!strncasecmp(word, acf->name, wordlen) && ++which > state) {
                        ret = strdup(acf->name);
                        break;
                }
        }
-       AST_LIST_UNLOCK(&acf_root);
+       AST_RWLIST_UNLOCK(&acf_root);
 
        return ret;
 }
@@ -1312,12 +1331,12 @@ struct ast_custom_function *ast_custom_function_find(const char *name)
 {
        struct ast_custom_function *acf = NULL;
 
-       AST_LIST_LOCK(&acf_root);
-       AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
+       AST_RWLIST_RDLOCK(&acf_root);
+       AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
                if (!strcmp(name, acf->name))
                        break;
        }
-       AST_LIST_UNLOCK(&acf_root);
+       AST_RWLIST_UNLOCK(&acf_root);
 
        return acf;
 }
@@ -1329,17 +1348,17 @@ int ast_custom_function_unregister(struct ast_custom_function *acf)
        if (!acf)
                return -1;
 
-       AST_LIST_LOCK(&acf_root);
-       AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
+       AST_RWLIST_WRLOCK(&acf_root);
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
                if (cur == acf) {
-                       AST_LIST_REMOVE_CURRENT(&acf_root, acflist);
+                       AST_RWLIST_REMOVE_CURRENT(&acf_root, acflist);
                        if (option_verbose > 1)
                                ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
                        break;
                }
        }
-       AST_LIST_TRAVERSE_SAFE_END
-       AST_LIST_UNLOCK(&acf_root);
+       AST_RWLIST_TRAVERSE_SAFE_END
+       AST_RWLIST_UNLOCK(&acf_root);
 
        return acf ? 0 : -1;
 }
@@ -1351,26 +1370,28 @@ int ast_custom_function_register(struct ast_custom_function *acf)
        if (!acf)
                return -1;
 
-       AST_LIST_LOCK(&acf_root);
+       AST_RWLIST_WRLOCK(&acf_root);
 
-       if (ast_custom_function_find(acf->name)) {
-               ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
-               AST_LIST_UNLOCK(&acf_root);
-               return -1;
+       AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
+               if (!strcmp(acf->name, cur->name)) {
+                       ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
+                       AST_RWLIST_UNLOCK(&acf_root);
+                       return -1;
+               }
        }
 
        /* Store in alphabetical order */
-       AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
                if (strcasecmp(acf->name, cur->name) < 0) {
-                       AST_LIST_INSERT_BEFORE_CURRENT(&acf_root, acf, acflist);
+                       AST_RWLIST_INSERT_BEFORE_CURRENT(&acf_root, acf, acflist);
                        break;
                }
        }
-       AST_LIST_TRAVERSE_SAFE_END
+       AST_RWLIST_TRAVERSE_SAFE_END
        if (!cur)
-               AST_LIST_INSERT_TAIL(&acf_root, acf, acflist);
+               AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
 
-       AST_LIST_UNLOCK(&acf_root);
+       AST_RWLIST_UNLOCK(&acf_root);
 
        if (option_verbose > 1)
                ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
@@ -1398,31 +1419,33 @@ static char *func_args(char *function)
        return args;
 }
 
-int ast_func_read(struct ast_channel *chan, char *function, char *workspace, size_t len)
+int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
 {
-       char *args = func_args(function);
-       struct ast_custom_function *acfptr = ast_custom_function_find(function);
+       char *copy = ast_strdupa(function);
+       char *args = func_args(copy);
+       struct ast_custom_function *acfptr = ast_custom_function_find(copy);
 
        if (acfptr == NULL)
-               ast_log(LOG_ERROR, "Function %s not registered\n", function);
+               ast_log(LOG_ERROR, "Function %s not registered\n", copy);
        else if (!acfptr->read)
-               ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
+               ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
        else
-               return acfptr->read(chan, function, args, workspace, len);
+               return acfptr->read(chan, copy, args, workspace, len);
        return -1;
 }
 
-int ast_func_write(struct ast_channel *chan, char *function, const char *value)
+int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
 {
-       char *args = func_args(function);
-       struct ast_custom_function *acfptr = ast_custom_function_find(function);
+       char *copy = ast_strdupa(function);
+       char *args = func_args(copy);
+       struct ast_custom_function *acfptr = ast_custom_function_find(copy);
 
        if (acfptr == NULL)
-               ast_log(LOG_ERROR, "Function %s not registered\n", function);
+               ast_log(LOG_ERROR, "Function %s not registered\n", copy);
        else if (!acfptr->write)
-               ast_log(LOG_ERROR, "Function %s cannot be written to\n", function);
+               ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
        else
-               return acfptr->write(chan, function, args, value);
+               return acfptr->write(chan, copy, args, value);
 
        return -1;
 }
@@ -1448,7 +1471,7 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
                nextexp = NULL;
                nextthing = strchr(whereweare, '$');
                if (nextthing) {
-                       switch(nextthing[1]) {
+                       switch (nextthing[1]) {
                        case '{':
                                nextvar = nextthing;
                                pos = nextvar - whereweare;
@@ -1527,8 +1550,8 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
                        if (isfunction) {
                                /* Evaluate function */
                                cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
-
-                               ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
                        } else {
                                /* Retrieve variable value */
                                pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
@@ -1552,7 +1575,7 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
                        needsub = 0;
 
                        /* Find the end of it */
-                       while(brackets && *vare) {
+                       while (brackets && *vare) {
                                if ((vare[0] == '$') && (vare[1] == '[')) {
                                        needsub++;
                                        brackets++;
@@ -1595,7 +1618,8 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
                        length = ast_expr(vars, cp2, count);
 
                        if (length) {
-                               ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
                                count -= length;
                                cp2 += length;
                        }
@@ -1619,7 +1643,7 @@ static void pbx_substitute_variables(char *passdata, int datalen, struct ast_cha
        memset(passdata, 0, datalen);
 
        /* No variables or expressions in e->data, so why scan it? */
-       if (!strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
+       if (e->data && !strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
                ast_copy_string(passdata, e->data, datalen);
                return;
        }
@@ -1648,19 +1672,21 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
 
        int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
 
-       ast_mutex_lock(&conlock);
+       ast_rdlock_contexts();
        e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
        if (e) {
                if (matching_action) {
-                       ast_mutex_unlock(&conlock);
+                       ast_unlock_contexts();
                        return -1;      /* success, we found it */
                } else if (action == E_FINDLABEL) { /* map the label to a priority */
                        res = e->priority;
-                       ast_mutex_unlock(&conlock);
+                       ast_unlock_contexts();
                        return res;     /* the priority we were looking for */
                } else {        /* spawn */
-                       app = pbx_findapp(e->app);
-                       ast_mutex_unlock(&conlock);
+                       if (!e->cached_app)
+                               e->cached_app = pbx_findapp(e->app);
+                       app = e->cached_app;
+                       ast_unlock_contexts();
                        if (!app) {
                                ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
                                return -1;
@@ -1674,7 +1700,8 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
                        if (option_debug) {
                                char atmp[80];
                                char atmp2[EXT_DATA_SIZE+100];
-                               ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
                                snprintf(atmp, sizeof(atmp), "STACK-%s-%s-%d", context, exten, priority);
                                snprintf(atmp2, sizeof(atmp2), "%s(\"%s\", \"%s\") %s",
                                        app->name, c->name, passdata, "in new stack");
@@ -1701,7 +1728,7 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
                        return pbx_exec(c, app, passdata);      /* 0 on success, -1 on failure */
                }
        } else if (q.swo) {     /* not found here, but in another switch */
-               ast_mutex_unlock(&conlock);
+               ast_unlock_contexts();
                if (matching_action)
                        return -1;
                else {
@@ -1712,7 +1739,7 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
                        return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
                }
        } else {        /* not found anywhere, see what happened */
-               ast_mutex_unlock(&conlock);
+               ast_unlock_contexts();
                switch (q.status) {
                case STATUS_NO_CONTEXT:
                        if (!matching_action)
@@ -1731,7 +1758,8 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
                                ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
                        break;
                default:
-                       ast_log(LOG_DEBUG, "Shouldn't happen!\n");
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Shouldn't happen!\n");
                }
 
                return (matching_action) ? 0 : -1;
@@ -1744,9 +1772,9 @@ static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *c
        struct ast_exten *e;
        struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
 
-       ast_mutex_lock(&conlock);
+       ast_rdlock_contexts();
        e = pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
-       ast_mutex_unlock(&conlock);
+       ast_unlock_contexts();
 
        return e;
 }
@@ -1864,9 +1892,9 @@ void ast_hint_state_changed(const char *device)
 {
        struct ast_hint *hint;
 
-       AST_LIST_LOCK(&hints);
+       AST_RWLIST_RDLOCK(&hints);
 
-       AST_LIST_TRAVERSE(&hints, hint, list) {
+       AST_RWLIST_TRAVERSE(&hints, hint, list) {
                struct ast_state_cb *cblist;
                char buf[AST_MAX_EXTENSION];
                char *parse = buf;
@@ -1900,7 +1928,7 @@ void ast_hint_state_changed(const char *device)
                hint->laststate = state;        /* record we saw the change */
        }
 
-       AST_LIST_UNLOCK(&hints);
+       AST_RWLIST_UNLOCK(&hints);
 }
 
 /*! \brief  ast_extension_state_add: Add watcher for extension states */
@@ -1913,19 +1941,19 @@ int ast_extension_state_add(const char *context, const char *exten,
 
        /* If there's no context and extension:  add callback to statecbs list */
        if (!context && !exten) {
-               AST_LIST_LOCK(&hints);
+               AST_RWLIST_WRLOCK(&hints);
 
                for (cblist = statecbs; cblist; cblist = cblist->next) {
                        if (cblist->callback == callback) {
                                cblist->data = data;
-                               AST_LIST_UNLOCK(&hints);
+                               AST_RWLIST_UNLOCK(&hints);
                                return 0;
                        }
                }
 
                /* Now insert the callback */
                if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
-                       AST_LIST_UNLOCK(&hints);
+                       AST_RWLIST_UNLOCK(&hints);
                        return -1;
                }
                cblist->id = 0;
@@ -1935,7 +1963,7 @@ int ast_extension_state_add(const char *context, const char *exten,
                cblist->next = statecbs;
                statecbs = cblist;
 
-               AST_LIST_UNLOCK(&hints);
+               AST_RWLIST_UNLOCK(&hints);
                return 0;
        }
 
@@ -1949,22 +1977,22 @@ int ast_extension_state_add(const char *context, const char *exten,
        }
 
        /* Find the hint in the list of hints */
-       AST_LIST_LOCK(&hints);
+       AST_RWLIST_WRLOCK(&hints);
 
-       AST_LIST_TRAVERSE(&hints, hint, list) {
+       AST_RWLIST_TRAVERSE(&hints, hint, list) {
                if (hint->exten == e)
                        break;
        }
 
        if (!hint) {
                /* We have no hint, sorry */
-               AST_LIST_UNLOCK(&hints);
+               AST_RWLIST_UNLOCK(&hints);
                return -1;
        }
 
        /* Now insert the callback in the callback list  */
        if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
-               AST_LIST_UNLOCK(&hints);
+               AST_RWLIST_UNLOCK(&hints);
                return -1;
        }
        cblist->id = stateid++;         /* Unique ID for this callback */
@@ -1974,7 +2002,7 @@ int ast_extension_state_add(const char *context, const char *exten,
        cblist->next = hint->callbacks;
        hint->callbacks = cblist;
 
-       AST_LIST_UNLOCK(&hints);
+       AST_RWLIST_UNLOCK(&hints);
        return cblist->id;
 }
 
@@ -1987,7 +2015,7 @@ int ast_extension_state_del(int id, ast_state_cb_type callback)
        if (!id && !callback)
                return -1;
 
-       AST_LIST_LOCK(&hints);
+       AST_RWLIST_WRLOCK(&hints);
 
        if (!id) {      /* id == 0 is a callback without extension */
                for (p_cur = &statecbs; *p_cur; p_cur = &(*p_cur)->next) {
@@ -1996,7 +2024,7 @@ int ast_extension_state_del(int id, ast_state_cb_type callback)
                }
        } else { /* callback with extension, find the callback based on ID */
                struct ast_hint *hint;
-               AST_LIST_TRAVERSE(&hints, hint, list) {
+               AST_RWLIST_TRAVERSE(&hints, hint, list) {
                        for (p_cur = &hint->callbacks; *p_cur; p_cur = &(*p_cur)->next) {
                                if ((*p_cur)->id == id)
                                        break;
@@ -2011,7 +2039,7 @@ int ast_extension_state_del(int id, ast_state_cb_type callback)
                free(cur);
                ret = 0;
        }
-       AST_LIST_UNLOCK(&hints);
+       AST_RWLIST_UNLOCK(&hints);
        return ret;
 }
 
@@ -2023,12 +2051,12 @@ static int ast_add_hint(struct ast_exten *e)
        if (!e)
                return -1;
 
-       AST_LIST_LOCK(&hints);
+       AST_RWLIST_WRLOCK(&hints);
 
        /* Search if hint exists, do nothing */
-       AST_LIST_TRAVERSE(&hints, hint, list) {
+       AST_RWLIST_TRAVERSE(&hints, hint, list) {
                if (hint->exten == e) {
-                       AST_LIST_UNLOCK(&hints);
+                       AST_RWLIST_UNLOCK(&hints);
                        if (option_debug > 1)
                                ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
                        return -1;
@@ -2039,15 +2067,15 @@ static int ast_add_hint(struct ast_exten *e)
                ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
 
        if (!(hint = ast_calloc(1, sizeof(*hint)))) {
-               AST_LIST_UNLOCK(&hints);
+               AST_RWLIST_UNLOCK(&hints);
                return -1;
        }
        /* Initialize and insert new item at the top */
        hint->exten = e;
        hint->laststate = ast_extension_state2(e);
-       AST_LIST_INSERT_HEAD(&hints, hint, list);
+       AST_RWLIST_INSERT_HEAD(&hints, hint, list);
 
-       AST_LIST_UNLOCK(&hints);
+       AST_RWLIST_UNLOCK(&hints);
        return 0;
 }
 
@@ -2057,15 +2085,15 @@ static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
        struct ast_hint *hint;
        int res = -1;
 
-       AST_LIST_LOCK(&hints);
-       AST_LIST_TRAVERSE(&hints, hint, list) {
+       AST_RWLIST_WRLOCK(&hints);
+       AST_RWLIST_TRAVERSE(&hints, hint, list) {
                if (hint->exten == oe) {
                        hint->exten = ne;
                        res = 0;
                        break;
                }
        }
-       AST_LIST_UNLOCK(&hints);
+       AST_RWLIST_UNLOCK(&hints);
 
        return res;
 }
@@ -2081,8 +2109,7 @@ static int ast_remove_hint(struct ast_exten *e)
        if (!e)
                return -1;
 
-       AST_LIST_LOCK(&hints);
-       AST_LIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
                if (hint->exten == e) {
                        cbprev = NULL;
                        cblist = hint->callbacks;
@@ -2094,14 +2121,13 @@ static int ast_remove_hint(struct ast_exten *e)
                                free(cbprev);
                        }
                        hint->callbacks = NULL;
-                       AST_LIST_REMOVE_CURRENT(&hints, list);
+                       AST_RWLIST_REMOVE_CURRENT(&hints, list);
                        free(hint);
                        res = 0;
                        break;
                }
        }
-       AST_LIST_TRAVERSE_SAFE_END
-       AST_LIST_UNLOCK(&hints);
+       AST_RWLIST_TRAVERSE_SAFE_END
 
        return res;
 }
@@ -2255,7 +2281,8 @@ static int __ast_pbx_run(struct ast_channel *c)
                        if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
                                /* Something bad happened, or a hangup has been requested. */
                                if (strchr("0123456789ABCDEF*#", res)) {
-                                       ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
+                                       if (option_debug)
+                                               ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
                                        pos = 0;
                                        dst_exten[pos++] = digit = res;
                                        dst_exten[pos] = '\0';
@@ -2290,8 +2317,9 @@ static int __ast_pbx_run(struct ast_channel *c)
                                c->whentohangup = 0;
                                c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
                        } else if (c->_softhangup) {
-                               ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
-                                       c->exten, c->priority);
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
+                                               c->exten, c->priority);
                                error = 1;
                                break;
                        }
@@ -2386,7 +2414,7 @@ static int __ast_pbx_run(struct ast_channel *c)
                if (c->cdr && ast_opt_end_cdr_before_h_exten)
                        ast_cdr_end(c->cdr);
                set_ext_pri(c, "h", 1);
-               while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
+               while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
                        if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
                                /* Something bad happened, or a hangup has been requested. */
                                if (option_debug)
@@ -2489,8 +2517,10 @@ enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
        if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
                ast_log(LOG_WARNING, "Failed to create new channel thread\n");
+               pthread_attr_destroy(&attr);
                return AST_PBX_FAILED;
        }
+       pthread_attr_destroy(&attr);
 
        return AST_PBX_SUCCESS;
 }
@@ -2527,7 +2557,7 @@ static struct ast_context *find_context_locked(const char *context)
 {
        struct ast_context *c = NULL;
 
-       ast_lock_contexts();
+       ast_rdlock_contexts();
        while ( (c = ast_walk_contexts(c)) ) {
                if (!strcmp(ast_get_context_name(c), context))
                        return c;
@@ -2568,7 +2598,7 @@ int ast_context_remove_include2(struct ast_context *con, const char *include, co
        struct ast_include *i, *pi = NULL;
        int ret = -1;
 
-       ast_mutex_lock(&con->lock);
+       ast_wrlock_context(con);
 
        /* find our include */
        for (i = con->includes; i; pi = i, i = i->next) {
@@ -2586,7 +2616,8 @@ int ast_context_remove_include2(struct ast_context *con, const char *include, co
                }
        }
 
-       ast_mutex_unlock(&con->lock);
+       ast_unlock_context(con);
+
        return ret;
 }
 
@@ -2621,7 +2652,7 @@ int ast_context_remove_switch2(struct ast_context *con, const char *sw, const ch
        struct ast_sw *i;
        int ret = -1;
 
-       ast_mutex_lock(&con->lock);
+       ast_wrlock_context(con);
 
        /* walk switches */
        AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
@@ -2636,7 +2667,7 @@ int ast_context_remove_switch2(struct ast_context *con, const char *sw, const ch
        }
        AST_LIST_TRAVERSE_SAFE_END
 
-       ast_mutex_unlock(&con->lock);
+       ast_unlock_context(con);
 
        return ret;
 }
@@ -2673,7 +2704,7 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
        struct ast_exten *exten, *prev_exten = NULL;
        struct ast_exten *peer;
 
-       ast_mutex_lock(&con->lock);
+       ast_wrlock_context(con);
 
        /* scan the extension list to find matching extension-registrar */
        for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
@@ -2683,7 +2714,7 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
        }
        if (!exten) {
                /* we can't find right extension */
-               ast_mutex_unlock(&con->lock);
+               ast_unlock_context(con);
                return -1;
        }
 
@@ -2710,7 +2741,7 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
                                break; /* found our priority */
                }
                if (!peer) { /* not found */
-                       ast_mutex_unlock(&con->lock);
+                       ast_unlock_context(con);
                        return -1;
                }
                /* we are first priority extension? */
@@ -2735,7 +2766,7 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
                destroy_exten(peer);
                /* XXX should we return -1 ? */
        }
-       ast_mutex_unlock(&con->lock);
+       ast_unlock_context(con);
        return 0;
 }
 
@@ -2750,7 +2781,7 @@ int ast_context_lockmacro(const char *context)
        struct ast_context *c = NULL;
        int ret = -1;
 
-       ast_lock_contexts();
+       ast_rdlock_contexts();
 
        while ((c = ast_walk_contexts(c))) {
                if (!strcmp(ast_get_context_name(c), context)) {
@@ -2778,7 +2809,7 @@ int ast_context_unlockmacro(const char *context)
        struct ast_context *c = NULL;
        int ret = -1;
 
-       ast_lock_contexts();
+       ast_rdlock_contexts();
 
        while ((c = ast_walk_contexts(c))) {
                if (!strcmp(ast_get_context_name(c), context)) {
@@ -2803,11 +2834,11 @@ int ast_register_application(const char *app, int (*execute)(struct ast_channel
        char tmps[80];
        int length;
 
-       AST_LIST_LOCK(&apps);
-       AST_LIST_TRAVERSE(&apps, tmp, list) {
+       AST_RWLIST_WRLOCK(&apps);
+       AST_RWLIST_TRAVERSE(&apps, tmp, list) {
                if (!strcasecmp(app, tmp->name)) {
                        ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
-                       AST_LIST_UNLOCK(&apps);
+                       AST_RWLIST_UNLOCK(&apps);
                        return -1;
                }
        }
@@ -2815,7 +2846,7 @@ int ast_register_application(const char *app, int (*execute)(struct ast_channel
        length = sizeof(*tmp) + strlen(app) + 1;
 
        if (!(tmp = ast_calloc(1, length))) {
-               AST_LIST_UNLOCK(&apps);
+               AST_RWLIST_UNLOCK(&apps);
                return -1;
        }
 
@@ -2825,20 +2856,20 @@ int ast_register_application(const char *app, int (*execute)(struct ast_channel
        tmp->description = description;
 
        /* Store in alphabetical order */
-       AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
                if (strcasecmp(tmp->name, cur->name) < 0) {
-                       AST_LIST_INSERT_BEFORE_CURRENT(&apps, tmp, list);
+                       AST_RWLIST_INSERT_BEFORE_CURRENT(&apps, tmp, list);
                        break;
                }
        }
-       AST_LIST_TRAVERSE_SAFE_END
+       AST_RWLIST_TRAVERSE_SAFE_END
        if (!cur)
-               AST_LIST_INSERT_TAIL(&apps, tmp, list);
+               AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
 
        if (option_verbose > 1)
                ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
 
-       AST_LIST_UNLOCK(&apps);
+       AST_RWLIST_UNLOCK(&apps);
 
        return 0;
 }
@@ -2851,50 +2882,50 @@ int ast_register_switch(struct ast_switch *sw)
 {
        struct ast_switch *tmp;
 
-       AST_LIST_LOCK(&switches);
-       AST_LIST_TRAVERSE(&switches, tmp, list) {
+       AST_RWLIST_WRLOCK(&switches);
+       AST_RWLIST_TRAVERSE(&switches, tmp, list) {
                if (!strcasecmp(tmp->name, sw->name)) {
-                       AST_LIST_UNLOCK(&switches);
+                       AST_RWLIST_UNLOCK(&switches);
                        ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
                        return -1;
                }
        }
-       AST_LIST_INSERT_TAIL(&switches, sw, list);
-       AST_LIST_UNLOCK(&switches);
+       AST_RWLIST_INSERT_TAIL(&switches, sw, list);
+       AST_RWLIST_UNLOCK(&switches);
 
        return 0;
 }
 
 void ast_unregister_switch(struct ast_switch *sw)
 {
-       AST_LIST_LOCK(&switches);
-       AST_LIST_REMOVE(&switches, sw, list);
-       AST_LIST_UNLOCK(&switches);
+       AST_RWLIST_WRLOCK(&switches);
+       AST_RWLIST_REMOVE(&switches, sw, list);
+       AST_RWLIST_UNLOCK(&switches);
 }
 
 /*
  * Help for CLI commands ...
  */
 static char show_applications_help[] =
-"Usage: core list applications [{like|describing} <text>]\n"
+"Usage: core show applications [{like|describing} <text>]\n"
 "       List applications which are currently available.\n"
 "       If 'like', <text> will be a substring of the app name\n"
 "       If 'describing', <text> will be a substring of the description\n";
 
 static char show_functions_help[] =
-"Usage: core list functions [like <text>]\n"
+"Usage: core show functions [like <text>]\n"
 "       List builtin functions, optionally only those matching a given string\n";
 
 static char show_switches_help[] =
-"Usage: core list switches\n"
+"Usage: core show switches\n"
 "       List registered switches\n";
 
 static char show_hints_help[] =
-"Usage: core list hints\n"
+"Usage: core show hints\n"
 "       List registered hints\n";
 
 static char show_globals_help[] =
-"Usage: core list globals\n"
+"Usage: core show globals\n"
 "       List current global dialplan variables and their values\n";
 
 static char show_application_help[] =
@@ -2906,7 +2937,7 @@ static char show_function_help[] =
 "       Describe a particular dialplan function.\n";
 
 static char show_dialplan_help[] =
-"Usage: dialplan show [exten@][context]\n"
+"Usage: core show dialplan [exten@][context]\n"
 "       Show dialplan\n";
 
 static char set_global_help[] =
@@ -2931,14 +2962,14 @@ static char *complete_show_application(const char *line, const char *word, int p
        int wordlen = strlen(word);
 
        /* return the n-th [partial] matching entry */
-       AST_LIST_LOCK(&apps);
-       AST_LIST_TRAVERSE(&apps, a, list) {
+       AST_RWLIST_RDLOCK(&apps);
+       AST_RWLIST_TRAVERSE(&apps, a, list) {
                if (!strncasecmp(word, a->name, wordlen) && ++which > state) {
                        ret = strdup(a->name);
                        break;
                }
        }
-       AST_LIST_UNLOCK(&apps);
+       AST_RWLIST_UNLOCK(&apps);
 
        return ret;
 }
@@ -2952,8 +2983,8 @@ static int handle_show_application(int fd, int argc, char *argv[])
                return RESULT_SHOWUSAGE;
 
        /* ... go through all applications ... */
-       AST_LIST_LOCK(&apps);
-       AST_LIST_TRAVERSE(&apps, a, list) {
+       AST_RWLIST_RDLOCK(&apps);
+       AST_RWLIST_TRAVERSE(&apps, a, list) {
                /* ... compare this application name with all arguments given
                 * to 'show application' command ... */
                for (app = 3; app < argc; app++) {
@@ -3002,7 +3033,7 @@ static int handle_show_application(int fd, int argc, char *argv[])
                        }
                }
        }
-       AST_LIST_UNLOCK(&apps);
+       AST_RWLIST_UNLOCK(&apps);
 
        /* we found at least one app? no? */
        if (no_registered_app) {
@@ -3013,7 +3044,7 @@ static int handle_show_application(int fd, int argc, char *argv[])
        return RESULT_SUCCESS;
 }
 
-/*! \brief  handle_show_hints: CLI support for listing registred dial plan hints */
+/*! \brief  handle_show_hints: CLI support for listing registered dial plan hints */
 static int handle_show_hints(int fd, int argc, char *argv[])
 {
        struct ast_hint *hint;
@@ -3021,14 +3052,15 @@ static int handle_show_hints(int fd, int argc, char *argv[])
        int watchers;
        struct ast_state_cb *watcher;
 
-       if (AST_LIST_EMPTY(&hints)) {
+       AST_RWLIST_RDLOCK(&hints);
+       if (AST_RWLIST_EMPTY(&hints)) {
                ast_cli(fd, "There are no registered dialplan hints\n");
+               AST_RWLIST_UNLOCK(&hints);
                return RESULT_SUCCESS;
        }
        /* ... we have hints ... */
        ast_cli(fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
-       AST_LIST_LOCK(&hints);
-       AST_LIST_TRAVERSE(&hints, hint, list) {
+       AST_RWLIST_TRAVERSE(&hints, hint, list) {
                watchers = 0;
                for (watcher = hint->callbacks; watcher; watcher = watcher->next)
                        watchers++;
@@ -3041,28 +3073,28 @@ static int handle_show_hints(int fd, int argc, char *argv[])
        }
        ast_cli(fd, "----------------\n");
        ast_cli(fd, "- %d hints registered\n", num);
-       AST_LIST_UNLOCK(&hints);
+       AST_RWLIST_UNLOCK(&hints);
        return RESULT_SUCCESS;
 }
 
-/*! \brief  handle_show_switches: CLI support for listing registred dial plan switches */
+/*! \brief  handle_show_switches: CLI support for listing registered dial plan switches */
 static int handle_show_switches(int fd, int argc, char *argv[])
 {
        struct ast_switch *sw;
 
-       AST_LIST_LOCK(&switches);
+       AST_RWLIST_RDLOCK(&switches);
 
-       if (AST_LIST_EMPTY(&switches)) {
-               AST_LIST_UNLOCK(&switches);
+       if (AST_RWLIST_EMPTY(&switches)) {
+               AST_RWLIST_UNLOCK(&switches);
                ast_cli(fd, "There are no registered alternative switches\n");
                return RESULT_SUCCESS;
        }
 
        ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
-       AST_LIST_TRAVERSE(&switches, sw, list)
+       AST_RWLIST_TRAVERSE(&switches, sw, list)
                ast_cli(fd, "%s: %s\n", sw->name, sw->description);
 
-       AST_LIST_UNLOCK(&switches);
+       AST_RWLIST_UNLOCK(&switches);
 
        return RESULT_SUCCESS;
 }
@@ -3074,11 +3106,11 @@ static int handle_show_applications(int fd, int argc, char *argv[])
        int total_match = 0;    /* Number of matches in like clause */
        int total_apps = 0;     /* Number of apps registered */
 
-       AST_LIST_LOCK(&apps);
+       AST_RWLIST_RDLOCK(&apps);
 
-       if (AST_LIST_EMPTY(&apps)) {
+       if (AST_RWLIST_EMPTY(&apps)) {
                ast_cli(fd, "There are no registered applications\n");
-               AST_LIST_UNLOCK(&apps);
+               AST_RWLIST_UNLOCK(&apps);
                return -1;
        }
 
@@ -3096,7 +3128,7 @@ static int handle_show_applications(int fd, int argc, char *argv[])
                ast_cli(fd, "    -= Matching Asterisk Applications =-\n");
        }
 
-       AST_LIST_TRAVERSE(&apps, a, list) {
+       AST_RWLIST_TRAVERSE(&apps, a, list) {
                int printapp = 0;
                total_apps++;
                if (like) {
@@ -3131,7 +3163,7 @@ static int handle_show_applications(int fd, int argc, char *argv[])
                ast_cli(fd, "    -= %d Applications Matching =-\n",total_match);
        }
 
-       AST_LIST_UNLOCK(&apps);
+       AST_RWLIST_UNLOCK(&apps);
 
        return RESULT_SUCCESS;
 }
@@ -3158,7 +3190,7 @@ static char *complete_show_dialplan_context(const char *line, const char *word,
        if (pos != 2)
                return NULL;
 
-       ast_lock_contexts();
+       ast_rdlock_contexts();
 
        wordlen = strlen(word);
 
@@ -3175,7 +3207,9 @@ static char *complete_show_dialplan_context(const char *line, const char *word,
        return ret;
 }
 
+/*! \brief Counters for the show dialplan manager command */
 struct dialplan_counters {
+       int total_items;
        int total_context;
        int total_exten;
        int total_prio;
@@ -3203,7 +3237,7 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten,
        struct ast_context *c = NULL;
        int res = 0, old_total_exten = dpc->total_exten;
 
-       ast_lock_contexts();
+       ast_rdlock_contexts();
 
        /* walk all contexts ... */
        while ( (c = ast_walk_contexts(c)) ) {
@@ -3218,7 +3252,7 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten,
 
                dpc->context_existence = 1;
 
-               ast_lock_context(c);
+               ast_rdlock_context(c);
 
                /* are we looking for exten too? if yes, we print context
                 * only if we find our extension.
@@ -3258,7 +3292,10 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten,
                        dpc->total_prio++;
 
                        /* write extension name and first peer */
-                       snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
+                       if (e->matchcid)
+                               snprintf(buf, sizeof(buf), "'%s' (CID match '%s') => ", ast_get_extension_name(e), e->cidmatch);
+                       else
+                               snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
 
                        print_ext(e, buf2, sizeof(buf2));
 
@@ -3401,18 +3438,236 @@ static int handle_show_dialplan(int fd, int argc, char *argv[])
        return RESULT_SUCCESS;
 }
 
+/*! \brief Send ack once */
+static void manager_dpsendack(struct mansession *s, const struct message *m)
+{
+       astman_send_listack(s, m, "DialPlan list will follow", "start");
+}
+
+/*! \brief Show dialplan extensions
+ * XXX this function is similar but not exactly the same as the CLI's
+ * show dialplan. Must check whether the difference is intentional or not.
+ */
+static int manager_show_dialplan_helper(struct mansession *s, const struct message *m,
+                                       const char *actionidtext, const char *context,
+                                       const char *exten, struct dialplan_counters *dpc,
+                                       struct ast_include *rinclude)
+{
+       struct ast_context *c;
+       int res=0, old_total_exten = dpc->total_exten;
+
+       if (ast_strlen_zero(exten))
+               exten = NULL;
+       if (ast_strlen_zero(context))
+               context = NULL;
+
+       if (option_debug > 2)
+               ast_log(LOG_DEBUG, "manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten);
+
+       /* try to lock contexts */
+       if (ast_rdlock_contexts()) {
+               astman_send_error(s, m, "Failed to lock contexts\r\n");
+               ast_log(LOG_WARNING, "Failed to lock contexts list for manager: listdialplan\n");
+               return -1;
+       }
+
+       c = NULL;               /* walk all contexts ... */
+       while ( (c = ast_walk_contexts(c)) ) {
+               struct ast_exten *e;
+               struct ast_include *i;
+               struct ast_ignorepat *ip;
+
+               if (context && strcmp(ast_get_context_name(c), context) != 0)
+                       continue;       /* not the name we want */
+
+               dpc->context_existence = 1;
+
+               if (option_debug > 2)
+                       ast_log(LOG_DEBUG, "manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c));
+
+               if (ast_rdlock_context(c)) {    /* failed to lock */
+                       if (option_debug > 2)
+                               ast_log(LOG_DEBUG, "manager_show_dialplan: Failed to lock context\n");
+                       continue;
+               }
+
+               /* XXX note- an empty context is not printed */
+               e = NULL;               /* walk extensions in context  */
+               while ( (e = ast_walk_context_extensions(c, e)) ) {
+                       struct ast_exten *p;
+
+                       /* looking for extension? is this our extension? */
+                       if (exten && !ast_extension_match(ast_get_extension_name(e), exten)) {
+                               /* not the one we are looking for, continue */
+                               if (option_debug > 2)
+                                       ast_log(LOG_DEBUG, "manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e));
+                               continue;
+                       }
+                       if (option_debug > 2)
+                               ast_log(LOG_DEBUG, "manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e));
+
+                       dpc->extension_existence = 1;
+
+                       /* may we print context info? */        
+                       dpc->total_context++;
+                       dpc->total_exten++;
+
+                       p = NULL;               /* walk next extension peers */
+                       while ( (p = ast_walk_extension_priorities(e, p)) ) {
+                               int prio = ast_get_extension_priority(p);
+
+                               dpc->total_prio++;
+                               if (!dpc->total_items++)
+                                       manager_dpsendack(s, m);
+                               astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
+                               astman_append(s, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) );
+
+                               /* XXX maybe make this conditional, if p != e ? */
+                               if (ast_get_extension_label(p))
+                                       astman_append(s, "ExtensionLabel: %s\r\n", ast_get_extension_label(p));
+
+                               if (prio == PRIORITY_HINT) {
+                                       astman_append(s, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p));
+                               } else {
+                                       astman_append(s, "Priority: %d\r\nApplication: %s\r\nAppData: %s\r\n", prio, ast_get_extension_app(p), (char *) ast_get_extension_app_data(p));
+                               }
+                               astman_append(s, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e));
+                       }
+               }
+
+               i = NULL;               /* walk included and write info ... */
+               while ( (i = ast_walk_context_includes(c, i)) ) {
+                       if (exten) {
+                               /* Check all includes for the requested extension */
+                               manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i);
+                       } else {
+                               if (!dpc->total_items++)
+                                       manager_dpsendack(s, m);
+                               astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
+                               astman_append(s, "Context: %s\r\nIncludeContext: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_include_name(i), ast_get_include_registrar(i));
+                               astman_append(s, "\r\n");
+                               if (option_debug > 2)
+                                       ast_log(LOG_DEBUG, "manager_show_dialplan: Found Included context: %s \n", ast_get_include_name(i));
+                       }
+               }
+
+               ip = NULL;      /* walk ignore patterns and write info ... */
+               while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
+                       const char *ipname = ast_get_ignorepat_name(ip);
+                       char ignorepat[AST_MAX_EXTENSION];
+
+                       snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
+                       if (!exten || ast_extension_match(ignorepat, exten)) {
+                               if (!dpc->total_items++)
+                                       manager_dpsendack(s, m);
+                               astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
+                               astman_append(s, "Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip));
+                               astman_append(s, "\r\n");
+                       }
+               }
+               if (!rinclude) {
+                       struct ast_sw *sw = NULL;
+                       while ( (sw = ast_walk_context_switches(c, sw)) ) {
+                               if (!dpc->total_items++)
+                                       manager_dpsendack(s, m);
+                               astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
+                               astman_append(s, "Context: %s\r\nSwitch: %s/%s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_registrar(sw)); 
+                               astman_append(s, "\r\n");
+                               if (option_debug > 2)
+                                       ast_log(LOG_DEBUG, "manager_show_dialplan: Found Switch : %s \n", ast_get_switch_name(sw));
+                       }
+               }
+
+               ast_unlock_context(c);
+       }
+       ast_unlock_contexts();
+
+       if (dpc->total_exten == old_total_exten) {
+               if (option_debug > 2)
+                       ast_log(LOG_DEBUG, "manager_show_dialplan: Found nothing new\n");
+               /* Nothing new under the sun */
+               return -1;
+       } else {
+               return res;
+       }
+}
+
+/*! \brief  Manager listing of dial plan */
+static int manager_show_dialplan(struct mansession *s, const struct message *m)
+{
+       const char *exten, *context;
+       const char *id = astman_get_header(m, "ActionID");
+       char idtext[256];
+       int res;
+
+       /* Variables used for different counters */
+       struct dialplan_counters counters;
+
+       if (id && !ast_strlen_zero(id))
+               snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
+       else
+               idtext[0] = '\0';
+
+       memset(&counters, 0, sizeof(counters));
+
+       exten = astman_get_header(m, "Extension");
+       context = astman_get_header(m, "Context");
+       
+       res = manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL);
+
+       if (context && !counters.context_existence) {
+               char errorbuf[BUFSIZ];
+       
+               snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s\r\n", context);
+               astman_send_error(s, m, errorbuf);
+               return 0;
+       }
+       if (exten && !counters.extension_existence) {
+               char errorbuf[BUFSIZ];
+
+               if (context)
+                       snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s\r\n", exten, context);
+               else
+                       snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context\r\n", exten);
+               astman_send_error(s, m, errorbuf);
+               return 0;
+       }
+
+       manager_event(EVENT_FLAG_CONFIG, "ShowDialPlanComplete",
+               "EventList: Complete\r\n"
+               "ListItems: %d\r\n"
+               "ListExtensions: %d\r\n"
+               "ListPriorities: %d\r\n"        
+               "ListContexts: %d\r\n"  
+               "%s"
+               "\r\n", counters.total_items, counters.total_exten, counters.total_prio, counters.total_context, idtext);
+
+       /* everything ok */
+       return 0;
+}
+
+static char mandescr_show_dialplan[] =
+"Description: Show dialplan contexts and extensions.\n"
+"Be aware that showing the full dialplan may take a lot of capacity\n"
+"Variables: \n"
+" ActionID: <id>               Action ID for this AMI transaction (optional)\n"
+" Extension: <extension>       Extension (Optional)\n"
+" Context: <context>           Context (Optional)\n"
+"\n";
+
+
 /*! \brief CLI support for listing global variables in a parseable way */
 static int handle_show_globals(int fd, int argc, char *argv[])
 {
        int i = 0;
        struct ast_var_t *newvariable;
 
-       ast_mutex_lock(&globalslock);
+       ast_rwlock_rdlock(&globalslock);
        AST_LIST_TRAVERSE (&globals, newvariable, entries) {
                i++;
                ast_cli(fd, "   %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
        }
-       ast_mutex_unlock(&globalslock);
+       ast_rwlock_unlock(&globalslock);
        ast_cli(fd, "\n    -- %d variables\n", i);
 
        return RESULT_SUCCESS;
@@ -3435,23 +3690,23 @@ static int handle_set_global(int fd, int argc, char *argv[])
  * CLI entries for upper commands ...
  */
 static struct ast_cli_entry pbx_cli[] = {
-       { { "core", "list", "applications", NULL },
+       { { "core", "show", "applications", NULL },
        handle_show_applications, "Shows registered dialplan applications",
        show_applications_help, complete_show_applications },
 
-       { { "core", "list", "functions", NULL },
+       { { "core", "show", "functions", NULL },
        handle_show_functions, "Shows registered dialplan functions",
        show_functions_help },
 
-       { { "core", "list", "switches", NULL },
+       { { "core", "show", "switches", NULL },
        handle_show_switches, "Show alternative switches",
        show_switches_help },
 
-       { { "core", "list", "hints", NULL },
+       { { "core", "show", "hints", NULL },
        handle_show_hints, "Show dialplan hints",
        show_hints_help },
 
-       { { "core", "list", "globals", NULL },
+       { { "core", "show", "globals", NULL },
        handle_show_globals, "Show global dialplan variables",
        show_globals_help },
 
@@ -3472,22 +3727,42 @@ static struct ast_cli_entry pbx_cli[] = {
        show_dialplan_help, complete_show_dialplan_context },
 };
 
+static void unreference_cached_app(struct ast_app *app)
+{
+       struct ast_context *context = NULL;
+       struct ast_exten *eroot = NULL, *e = NULL;
+
+       ast_rdlock_contexts();
+       while ((context = ast_walk_contexts(context))) {
+               while ((eroot = ast_walk_context_extensions(context, eroot))) {
+                       while ((e = ast_walk_extension_priorities(eroot, e))) {
+                               if (e->cached_app == app)
+                                       e->cached_app = NULL;
+                       }
+               }
+       }
+       ast_unlock_contexts();
+
+       return;
+}
+
 int ast_unregister_application(const char *app)
 {
        struct ast_app *tmp;
 
-       AST_LIST_LOCK(&apps);
-       AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
+       AST_RWLIST_WRLOCK(&apps);
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
                if (!strcasecmp(app, tmp->name)) {
-                       AST_LIST_REMOVE_CURRENT(&apps, list);
+                       unreference_cached_app(tmp);
+                       AST_RWLIST_REMOVE_CURRENT(&apps, list);
                        if (option_verbose > 1)
                                ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
                        free(tmp);
                        break;
                }
        }
-       AST_LIST_TRAVERSE_SAFE_END
-       AST_LIST_UNLOCK(&apps);
+       AST_RWLIST_TRAVERSE_SAFE_END
+       AST_RWLIST_UNLOCK(&apps);
 
        return tmp ? 0 : -1;
 }
@@ -3498,7 +3773,7 @@ static struct ast_context *__ast_context_create(struct ast_context **extcontexts
        int length = sizeof(struct ast_context) + strlen(name) + 1;
 
        if (!extcontexts) {
-               ast_mutex_lock(&conlock);
+               ast_wrlock_contexts();
                local_contexts = &contexts;
        } else
                local_contexts = extcontexts;
@@ -3510,12 +3785,12 @@ static struct ast_context *__ast_context_create(struct ast_context **extcontexts
                                tmp = NULL;
                        }
                        if (!extcontexts)
-                               ast_mutex_unlock(&conlock);
+                               ast_unlock_contexts();
                        return tmp;
                }
        }
        if ((tmp = ast_calloc(1, length))) {
-               ast_mutex_init(&tmp->lock);
+               ast_rwlock_init(&tmp->lock);
                ast_mutex_init(&tmp->macrolock);
                strcpy(tmp->name, name);
                tmp->root = NULL;
@@ -3531,7 +3806,7 @@ static struct ast_context *__ast_context_create(struct ast_context **extcontexts
        }
 
        if (!extcontexts)
-               ast_mutex_unlock(&conlock);
+               ast_unlock_contexts();
        return tmp;
 }
 
@@ -3576,11 +3851,11 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
           in addition, the locks _must_ be taken in this order, because there are already
           other code paths that use this order
        */
-       ast_mutex_lock(&conlock);
-       AST_LIST_LOCK(&hints);
+       ast_wrlock_contexts();
+       AST_RWLIST_WRLOCK(&hints);
 
        /* preserve all watchers for hints associated with this registrar */
-       AST_LIST_TRAVERSE(&hints, hint, list) {
+       AST_RWLIST_TRAVERSE(&hints, hint, list) {
                if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
                        length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
                        if (!(this = ast_calloc(1, length)))
@@ -3599,7 +3874,8 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
        tmp = *extcontexts;
        if (registrar) {
                /* XXX remove previous contexts from same registrar */
-               ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
                __ast_context_destroy(NULL,registrar);
                while (tmp) {
                        lasttmp = tmp;
@@ -3627,7 +3903,7 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
        while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
                exten = ast_hint_extension(NULL, this->context, this->exten);
                /* Find the hint in the list of hints */
-               AST_LIST_TRAVERSE(&hints, hint, list) {
+               AST_RWLIST_TRAVERSE(&hints, hint, list) {
                        if (hint->exten == exten)
                                break;
                }
@@ -3652,8 +3928,8 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
                free(this);
        }
 
-       AST_LIST_UNLOCK(&hints);
-       ast_mutex_unlock(&conlock);
+       AST_RWLIST_UNLOCK(&hints);
+       ast_unlock_contexts();
 
        return;
 }
@@ -3957,13 +4233,13 @@ int ast_context_add_include2(struct ast_context *con, const char *value,
        new_include->next      = NULL;
        new_include->registrar = registrar;
 
-       ast_mutex_lock(&con->lock);
+       ast_wrlock_context(con);
 
        /* ... go to last include and check if context is already included too... */
        for (i = con->includes; i; i = i->next) {
                if (!strcasecmp(i->name, new_include->name)) {
                        free(new_include);
-                       ast_mutex_unlock(&con->lock);
+                       ast_unlock_context(con);
                        errno = EEXIST;
                        return -1;
                }
@@ -3977,7 +4253,8 @@ int ast_context_add_include2(struct ast_context *con, const char *value,
                con->includes = new_include;
        if (option_verbose > 2)
                ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
-       ast_mutex_unlock(&con->lock);
+
+       ast_unlock_context(con);
 
        return 0;
 }
@@ -4047,13 +4324,13 @@ int ast_context_add_switch2(struct ast_context *con, const char *value,
        new_sw->registrar = registrar;
 
        /* ... try to lock this context ... */
-       ast_mutex_lock(&con->lock);
+       ast_wrlock_context(con);
 
        /* ... go to last sw and check if context is already swd too... */
        AST_LIST_TRAVERSE(&con->alts, i, list) {
                if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
                        free(new_sw);
-                       ast_mutex_unlock(&con->lock);
+                       ast_unlock_context(con);
                        errno = EEXIST;
                        return -1;
                }
@@ -4065,7 +4342,7 @@ int ast_context_add_switch2(struct ast_context *con, const char *value,
        if (option_verbose > 2)
                ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
 
-       ast_mutex_unlock(&con->lock);
+       ast_unlock_context(con);
 
        return 0;
 }
@@ -4090,7 +4367,7 @@ int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat
 {
        struct ast_ignorepat *ip, *ipl = NULL;
 
-       ast_mutex_lock(&con->lock);
+       ast_wrlock_context(con);
 
        for (ip = con->ignorepats; ip; ip = ip->next) {
                if (!strcmp(ip->pattern, ignorepat) &&
@@ -4102,13 +4379,13 @@ int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat
                                con->ignorepats = ip->next;
                                free(ip);
                        }
-                       ast_mutex_unlock(&con->lock);
+                       ast_unlock_context(con);
                        return 0;
                }
                ipl = ip;
        }
 
-       ast_mutex_unlock(&con->lock);
+       ast_unlock_context(con);
        errno = EINVAL;
        return -1;
 }
@@ -4143,12 +4420,12 @@ int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const
        strcpy((char *)ignorepat->pattern, value);
        ignorepat->next = NULL;
        ignorepat->registrar = registrar;
-       ast_mutex_lock(&con->lock);
+       ast_wrlock_context(con);
        for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
                ignorepatl = ignorepatc;
                if (!strcasecmp(ignorepatc->pattern, value)) {
                        /* Already there */
-                       ast_mutex_unlock(&con->lock);
+                       ast_unlock_context(con);
                        errno = EEXIST;
                        return -1;
                }
@@ -4157,7 +4434,7 @@ int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const
                ignorepatl->next = ignorepat;
        else
                con->ignorepats = ignorepat;
-       ast_mutex_unlock(&con->lock);
+       ast_unlock_context(con);
        return 0;
 
 }
@@ -4228,12 +4505,10 @@ int ast_async_goto(struct ast_channel *chan, const char *context, const char *ex
                /* In order to do it when the channel doesn't really exist within
                   the PBX, we have to make a new channel, masquerade, and start the PBX
                   at the new location */
-               struct ast_channel *tmpchan = ast_channel_alloc(0);
+               struct ast_channel *tmpchan = ast_channel_alloc(0, chan->_state, 0, 0, "AsyncGoto/%s", chan->name);
                if (!tmpchan)
                        res = -1;
                else {
-                       ast_string_field_build(tmpchan, name, "AsyncGoto/%s", chan->name);
-                       ast_setstate(tmpchan, chan->_state);
                        /* Make formats okay */
                        tmpchan->readformat = chan->readformat;
                        tmpchan->writeformat = chan->writeformat;
@@ -4279,7 +4554,7 @@ static int ext_strncpy(char *dst, const char *src, int len)
        int count=0;
 
        while (*src && (count < len - 1)) {
-               switch(*src) {
+               switch (*src) {
                case ' ':
                        /*      otherwise exten => [a-b],1,... doesn't work */
                        /*              case '-': */
@@ -4297,10 +4572,6 @@ static int ext_strncpy(char *dst, const char *src, int len)
        return count;
 }
 
-static void null_datad(void *foo)
-{
-}
-
 /*! \brief add the extension in the priority chain.
  * returns 0 on success, -1 on failure
  */
@@ -4322,7 +4593,8 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
                   replacement?  If so, replace, otherwise, bonk. */
                if (!replace) {
                        ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
-                       tmp->datad(tmp->data);
+                       if (tmp->datad)
+                               tmp->datad(tmp->data);
                        free(tmp);
                        return -1;
                }
@@ -4340,7 +4612,8 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
                if (tmp->priority == PRIORITY_HINT)
                        ast_change_hint(e,tmp);
                /* Destroy the old one */
-               e->datad(e->data);
+               if (e->datad)
+                       e->datad(e->data);
                free(e);
        } else {        /* Slip ourselves in just before e */
                tmp->peer = e;
@@ -4406,12 +4679,12 @@ int ast_add_extension2(struct ast_context *con,
        /* if we are adding a hint, and there are global variables, and the hint
           contains variable references, then expand them
        */
-       ast_mutex_lock(&globalslock);
+       ast_rwlock_rdlock(&globalslock);
        if (priority == PRIORITY_HINT && AST_LIST_FIRST(&globals) && strstr(application, "${")) {
                pbx_substitute_variables_varshead(&globals, application, expand_buf, sizeof(expand_buf));
                application = expand_buf;
        }
-       ast_mutex_unlock(&globalslock);
+       ast_rwlock_unlock(&globalslock);
 
        length = sizeof(struct ast_exten);
        length += strlen(extension) + 1;
@@ -4424,8 +4697,6 @@ int ast_add_extension2(struct ast_context *con,
                length ++;      /* just the '\0' */
 
        /* Be optimistic:  Build the extension structure first */
-       if (datad == NULL)
-               datad = null_datad;
        if (!(tmp = ast_calloc(1, length)))
                return -1;
 
@@ -4454,7 +4725,7 @@ int ast_add_extension2(struct ast_context *con,
        tmp->datad = datad;
        tmp->registrar = registrar;
 
-       ast_mutex_lock(&con->lock);
+       ast_wrlock_context(con);
        res = 0; /* some compilers will think it is uninitialized otherwise */
        for (e = con->root; e; el = e, e = e->next) {   /* scan the extension list */
                res = ext_cmp(e->exten, extension);
@@ -4473,7 +4744,7 @@ int ast_add_extension2(struct ast_context *con,
        }
        if (e && res == 0) { /* exact match, insert in the pri chain */
                res = add_pri(con, tmp, el, e, replace);
-               ast_mutex_unlock(&con->lock);
+               ast_unlock_context(con);
                if (res < 0) {
                        errno = EEXIST; /* XXX do we care ? */
                        return 0; /* XXX should we return -1 maybe ? */
@@ -4488,17 +4759,19 @@ int ast_add_extension2(struct ast_context *con,
                        el->next = tmp;
                else
                        con->root = tmp;
-               ast_mutex_unlock(&con->lock);
+               ast_unlock_context(con);
                if (tmp->priority == PRIORITY_HINT)
                        ast_add_hint(tmp);
        }
        if (option_debug) {
                if (tmp->matchcid) {
-                       ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n",
-                               tmp->exten, tmp->priority, tmp->cidmatch, con->name);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n",
+                                       tmp->exten, tmp->priority, tmp->cidmatch, con->name);
                } else {
-                       ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n",
-                               tmp->exten, tmp->priority, con->name);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n",
+                                       tmp->exten, tmp->priority, con->name);
                }
        }
        if (option_verbose > 2) {
@@ -4590,7 +4863,7 @@ static void *async_wait(void *data)
 static int ast_pbx_outgoing_cdr_failed(void)
 {
        /* allocate a channel */
-       struct ast_channel *chan = ast_channel_alloc(0);
+       struct ast_channel *chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, 0);
 
        if (!chan)
                return -1;  /* failure */
@@ -4604,7 +4877,7 @@ static int ast_pbx_outgoing_cdr_failed(void)
        }
 
        /* allocation of the cdr was successful */
-       ast_cdr_init(chan->cdr, chan);  /* initilize our channel's cdr */
+       ast_cdr_init(chan->cdr, chan);  /* initialize our channel's cdr */
        ast_cdr_start(chan->cdr);       /* record the start and stop time */
        ast_cdr_end(chan->cdr);
        ast_cdr_failed(chan->cdr);      /* set the status to failed */
@@ -4623,7 +4896,15 @@ int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout
        pthread_attr_t attr;
 
        if (sync) {
-               LOAD_OH(oh);
+               oh.context = context;
+               oh.exten = exten;
+               oh.priority = priority;
+               oh.cid_num = cid_num;
+               oh.cid_name = cid_name;
+               oh.account = account;
+               oh.vars = vars;
+               oh.parent_channel = NULL;
+
                chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
                if (channel) {
                        *channel = chan;
@@ -4642,7 +4923,7 @@ int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout
                                        goto outgoing_exten_cleanup;
                                }
                                /* allocation of the cdr was successful */
-                               ast_cdr_init(chan->cdr, chan);  /* initilize our channel's cdr */
+                               ast_cdr_init(chan->cdr, chan);  /* initialize our channel's cdr */
                                ast_cdr_start(chan->cdr);
                        }
                        if (chan->_state == AST_STATE_UP) {
@@ -4675,7 +4956,7 @@ int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout
                                if (option_verbose > 3)
                                        ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
 
-                               if(chan->cdr) { /* update the cdr */
+                               if (chan->cdr) { /* update the cdr */
                                        /* here we update the status of the call, which sould be busy.
                                         * if that fails then we set the status to failed */
                                        if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
@@ -4703,9 +4984,8 @@ int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout
                        /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
                        /* check if "failed" exists */
                        if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
-                               chan = ast_channel_alloc(0);
+                               chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "OutgoingSpoolFailed");
                                if (chan) {
-                                       ast_string_field_set(chan, name, "OutgoingSpoolFailed");
                                        if (!ast_strlen_zero(context))
                                                ast_copy_string(chan->context, context, sizeof(chan->context));
                                        set_ext_pri(chan, "failed", 1);
@@ -4750,8 +5030,10 @@ int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout
                        }
                        ast_hangup(chan);
                        res = -1;
+                       pthread_attr_destroy(&attr);
                        goto outgoing_exten_cleanup;
                }
+               pthread_attr_destroy(&attr);
                res = 0;
        }
 outgoing_exten_cleanup:
@@ -4808,14 +5090,14 @@ int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout,
                                ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
                        } else {
                                chan->cdr = ast_cdr_alloc();   /* allocate a cdr for the channel */
-                               if(!chan->cdr) {
+                               if (!chan->cdr) {
                                        /* allocation of the cdr failed */
                                        free(chan->pbx);
                                        res = -1;
                                        goto outgoing_app_cleanup;
                                }
                                /* allocation of the cdr was successful */
-                               ast_cdr_init(chan->cdr, chan);  /* initilize our channel's cdr */
+                               ast_cdr_init(chan->cdr, chan);  /* initialize our channel's cdr */
                                ast_cdr_start(chan->cdr);
                        }
                        ast_set_variables(chan, vars);
@@ -4853,6 +5135,7 @@ int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout,
                                                        if (locked_channel)
                                                                *locked_channel = chan;
                                                }
+                                               pthread_attr_destroy(&attr);
                                        }
                                }
                        } else {
@@ -4911,11 +5194,13 @@ int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout,
                                ast_channel_unlock(chan);
                        ast_hangup(chan);
                        res = -1;
+                       pthread_attr_destroy(&attr);
                        goto outgoing_app_cleanup;
                } else {
                        if (locked_channel)
                                *locked_channel = chan;
                }
+               pthread_attr_destroy(&attr);
                res = 0;
        }
 outgoing_app_cleanup:
@@ -4931,19 +5216,21 @@ void __ast_context_destroy(struct ast_context *con, const char *registrar)
        struct ast_exten *e, *el, *en;
        struct ast_ignorepat *ipi;
 
-       ast_mutex_lock(&conlock);
+       ast_wrlock_contexts();
        for (tmp = contexts; tmp; ) {
                struct ast_context *next;       /* next starting point */
                for (; tmp; tmpl = tmp, tmp = tmp->next) {
-                       ast_log(LOG_DEBUG, "check ctx %s %s\n", tmp->name, tmp->registrar);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "check ctx %s %s\n", tmp->name, tmp->registrar);
                        if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
                             (!con || !strcasecmp(tmp->name, con->name)) )
                                break;  /* found it */
                }
                if (!tmp)       /* not found, we are done */
                        break;
-               ast_mutex_lock(&tmp->lock);
-               ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
+               ast_wrlock_context(tmp);
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
                next = tmp->next;
                if (tmpl)
                        tmpl->next = next;
@@ -4951,7 +5238,7 @@ void __ast_context_destroy(struct ast_context *con, const char *registrar)
                        contexts = next;
                /* Okay, now we're safe to let it go -- in a sense, we were
                   ready to let it go as soon as we locked it. */
-               ast_mutex_unlock(&tmp->lock);
+               ast_unlock_context(tmp);
                for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
                        struct ast_include *tmpil = tmpi;
                        tmpi = tmpi->next;
@@ -4974,12 +5261,12 @@ void __ast_context_destroy(struct ast_context *con, const char *registrar)
                        e = e->next;
                        destroy_exten(el);
                }
-               ast_mutex_destroy(&tmp->lock);
+               ast_rwlock_destroy(&tmp->lock);
                free(tmp);
                /* if we have a specific match, we are done, otherwise continue */
                tmp = con ? NULL : next;
        }
-       ast_mutex_unlock(&conlock);
+       ast_unlock_contexts();
 }
 
 void ast_context_destroy(struct ast_context *con, const char *registrar)
@@ -4991,12 +5278,14 @@ static void wait_for_hangup(struct ast_channel *chan, void *data)
 {
        int res;
        struct ast_frame *f;
+       double waitsec;
        int waittime;
 
-       if (ast_strlen_zero(data) || (sscanf(data, "%d", &waittime) != 1) || (waittime < 0))
-               waittime = -1;
-       if (waittime > -1) {
-               ast_safe_sleep(chan, waittime * 1000);
+       if (ast_strlen_zero(data) || (sscanf(data, "%lg", &waitsec) != 1) || (waitsec < 0))
+               waitsec = -1;
+       if (waitsec > -1) {
+               waittime = waitsec * 1000.0;
+               ast_safe_sleep(chan, waittime);
        } else do {
                res = ast_waitfor(chan, -1);
                if (res < 0)
@@ -5059,21 +5348,11 @@ static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
 {
        int delay = 0;
-       int res;
 
-       if (chan->_state == AST_STATE_UP)
-               delay = 0;
-       else if (!ast_strlen_zero(data))
+       if ((chan->_state != AST_STATE_UP) && !ast_strlen_zero(data))
                delay = atoi(data);
 
-       res = ast_answer(chan);
-       if (res)
-               return res;
-
-       if (delay)
-               res = ast_safe_sleep(chan, delay);
-
-       return res;
+       return __ast_answer(chan, delay);
 }
 
 AST_APP_OPTIONS(resetcdr_opts, {
@@ -5214,11 +5493,12 @@ static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
  */
 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
 {
+       double s;
        int ms;
 
        /* Wait for "n" seconds */
-       if (data && (ms = atof(data)) > 0) {
-               ms *= 1000;
+       if (data && (s = atof(data)) > 0.0) {
+               ms = s*1000.0;
                return ast_safe_sleep(chan, ms);
        }
        return 0;
@@ -5230,6 +5510,7 @@ static int pbx_builtin_wait(struct ast_channel *chan, void *data)
 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
 {
        int ms, res;
+       double s;
        struct ast_flags flags = {0};
        char *opts[1] = { NULL };
        char *parse;
@@ -5253,12 +5534,13 @@ static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
                ast_indicate_data(chan, AST_CONTROL_HOLD, opts[0], strlen(opts[0]));
 
        /* Wait for "n" seconds */
-       if (args.timeout && (ms = atof(args.timeout)) > 0)
-                ms *= 1000;
+       if (args.timeout && (s = atof(args.timeout)) > 0)
+                ms = s * 1000.0;
        else if (chan->pbx)
                ms = chan->pbx->rtimeout * 1000;
        else
                ms = 10000;
+
        res = ast_waitfordigit(chan, ms);
        if (!res) {
                if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
@@ -5305,10 +5587,10 @@ static int pbx_builtin_background(struct ast_channel *chan, void *data)
 
        AST_STANDARD_APP_ARGS(args, parse);
 
-       if (!args.lang)
+       if (ast_strlen_zero(args.lang))
                args.lang = (char *)chan->language;     /* XXX this is const */
 
-       if (!args.context)
+       if (ast_strlen_zero(args.context))
                args.context = chan->context;
 
        if (args.options) {
@@ -5375,7 +5657,7 @@ static int pbx_builtin_goto(struct ast_channel *chan, void *data)
 }
 
 
-int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size)
+int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf)
 {
        struct ast_var_t *variables;
        const char *var, *val;
@@ -5384,13 +5666,14 @@ int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t
        if (!chan)
                return 0;
 
-       memset(buf, 0, size);
+       (*buf)->used = 0;
+       (*buf)->str[0] = '\0';
 
        AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
                if ((var=ast_var_name(variables)) && (val=ast_var_value(variables))
                   /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
                   ) {
-                       if (ast_build_string(&buf, &size, "%s=%s\n", var, val)) {
+                       if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
                                ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
                                break;
                        } else
@@ -5418,7 +5701,7 @@ const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name
                if (!places[i])
                        continue;
                if (places[i] == &globals)
-                       ast_mutex_lock(&globalslock);
+                       ast_rwlock_rdlock(&globalslock);
                AST_LIST_TRAVERSE(places[i], variables, entries) {
                        if (!strcmp(name, ast_var_name(variables))) {
                                ret = ast_var_value(variables);
@@ -5426,7 +5709,7 @@ const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name
                        }
                }
                if (places[i] == &globals)
-                       ast_mutex_unlock(&globalslock);
+                       ast_rwlock_unlock(&globalslock);
                if (ret)
                        break;
        }
@@ -5454,10 +5737,10 @@ void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, cons
                        ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
                newvariable = ast_var_assign(name, value);
                if (headp == &globals)
-                       ast_mutex_lock(&globalslock);
+                       ast_rwlock_wrlock(&globalslock);
                AST_LIST_INSERT_HEAD(headp, newvariable, entries);
                if (headp == &globals)
-                       ast_mutex_unlock(&globalslock);
+                       ast_rwlock_unlock(&globalslock);
        }
 }
 
@@ -5485,7 +5768,7 @@ void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const
        }
 
        if (headp == &globals)
-               ast_mutex_lock(&globalslock);
+               ast_rwlock_wrlock(&globalslock);
        AST_LIST_TRAVERSE (headp, newvariable, entries) {
                if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
                        /* there is already such a variable, delete it */
@@ -5503,7 +5786,7 @@ void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const
        }
 
        if (headp == &globals)
-               ast_mutex_unlock(&globalslock);
+               ast_rwlock_unlock(&globalslock);
 }
 
 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
@@ -5581,10 +5864,10 @@ void pbx_builtin_clear_globals(void)
 {
        struct ast_var_t *vardata;
 
-       ast_mutex_lock(&globalslock);
+       ast_rwlock_wrlock(&globalslock);
        while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
                ast_var_delete(vardata);
-       ast_mutex_unlock(&globalslock);
+       ast_rwlock_unlock(&globalslock);
 }
 
 int pbx_checkcondition(const char *condition)
@@ -5615,7 +5898,8 @@ static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
        branch = pbx_checkcondition(condition) ? branch1 : branch2;
 
        if (ast_strlen_zero(branch)) {
-               ast_log(LOG_DEBUG, "Not taking any branch\n");
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "Not taking any branch\n");
                return 0;
        }
 
@@ -5694,33 +5978,46 @@ int load_pbx(void)
                        return -1;
                }
        }
+       
+       /* Register manager application */
+       ast_manager_register2("ShowDialPlan", EVENT_FLAG_CONFIG, manager_show_dialplan, "List dialplan", mandescr_show_dialplan);
        return 0;
 }
 
 /*
  * Lock context list functions ...
  */
-int ast_lock_contexts()
+int ast_wrlock_contexts()
+{
+       return ast_rwlock_wrlock(&conlock);
+}
+
+int ast_rdlock_contexts()
 {
-       return ast_mutex_lock(&conlock);
+       return ast_rwlock_rdlock(&conlock);
 }
 
 int ast_unlock_contexts()
 {
-       return ast_mutex_unlock(&conlock);
+       return ast_rwlock_unlock(&conlock);
 }
 
 /*
  * Lock context ...
  */
-int ast_lock_context(struct ast_context *con)
+int ast_wrlock_context(struct ast_context *con)
+{
+       return ast_rwlock_wrlock(&con->lock);
+}
+
+int ast_rdlock_context(struct ast_context *con)
 {
-       return ast_mutex_lock(&con->lock);
+       return ast_rwlock_rdlock(&con->lock);
 }
 
 int ast_unlock_context(struct ast_context *con)
 {
-       return ast_mutex_unlock(&con->lock);
+       return ast_rwlock_unlock(&con->lock);
 }
 
 /*