diff --git a/include/asterisk/lock.h b/include/asterisk/lock.h
index 943c7ffe61fdd1cf9aadbd9e3a40f246463c9013..573fc0c002a95e370f389f9b9da2d5aa7a1bd641 100644
--- a/include/asterisk/lock.h
+++ b/include/asterisk/lock.h
@@ -549,6 +549,82 @@ static void  __attribute__((destructor)) fini_##rwlock(void) \
 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock, AST_RWLOCK_INIT_VALUE, 1)
 #define AST_RWLOCK_DEFINE_STATIC_NOTRACKING(rwlock) __AST_RWLOCK_DEFINE(static, rwlock, AST_RWLOCK_INIT_VALUE_NOTRACKING, 0)
 
+/*!
+ * \brief Scoped Locks
+ *
+ * Scoped locks provide a way to use RAII locks. In other words,
+ * declaration of a scoped lock will automatically define and lock
+ * the lock. When the lock goes out of scope, it will automatically
+ * be unlocked.
+ *
+ * \example
+ * int some_function(struct ast_channel *chan)
+ * {
+ *     SCOPED_LOCK(lock, chan, ast_channel_lock, ast_channel_unlock);
+ *
+ *     if (!strcmp(ast_channel_name(chan, "foo")) {
+ *         return 0;
+ *     }
+ *
+ *     return -1;
+ * }
+ *
+ * In the above example, neither return path requires explicit unlocking
+ * of the channel.
+ *
+ * \note
+ * Care should be taken when using SCOPED_LOCKS in conjunction with ao2 objects.
+ * ao2 objects should be unlocked before they are unreffed. Since SCOPED_LOCK runs
+ * once the variable goes out of scope, this can easily lead to situations where the
+ * variable gets unlocked after it is unreffed.
+ *
+ * \param varname The unique name to give to the scoped lock. You are not likely to reference
+ * this outside of the SCOPED_LOCK invocation.
+ * \param lock The variable to lock. This can be anything that can be passed to a locking
+ * or unlocking function.
+ * \param lockfunc The function to call to lock the lock
+ * \param unlockfunc The function to call to unlock the lock
+ */
+#define SCOPED_LOCK(varname, lock, lockfunc, unlockfunc) \
+	auto void _dtor_ ## varname (typeof((lock)) * v); \
+	auto void _dtor_ ## varname (typeof((lock)) * v) { unlockfunc(*v); } \
+	typeof((lock)) varname __attribute__((cleanup(_dtor_ ## varname))) = lock; lockfunc((lock))
+
+/*!
+ * \brief scoped lock specialization for mutexes
+ */
+#define SCOPED_MUTEX(varname, lock) SCOPED_LOCK(varname, (lock), ast_mutex_lock, ast_mutex_unlock)
+
+/*!
+ * \brief scoped lock specialization for read locks
+ */
+#define SCOPED_RDLOCK(varname, lock) SCOPED_LOCK(varname, (lock), ast_rwlock_rdlock, ast_rwlock_unlock)
+
+/*!
+ * \brief scoped lock specialization for write locks
+ */
+#define SCOPED_WRLOCK(varname, lock) SCOPED_LOCK(varname, (lock), ast_rwlock_wrlock, ast_rwlock_unlock)
+
+/*!
+ * \brief scoped lock specialization for ao2 mutexes.
+ */
+#define SCOPED_AO2LOCK(varname, obj) SCOPED_LOCK(varname, (obj), ao2_lock, ao2_unlock)
+
+/*!
+ * \brief scoped lock specialization for ao2 read locks.
+ */
+#define SCOPED_AO2RDLOCK(varname, obj) SCOPED_LOCK(varname, (obj), ao2_rdlock, ao2_unlock)
+
+/*!
+ * \brief scoped lock specialization for ao2 write locks.
+ */
+#define SCOPED_AO2WRLOCK(varname, obj) SCOPED_LOCK(varname, (obj), ao2_wrlock, ao2_unlock)
+
+/*!
+ * \brief scoped lock specialization for channels.
+ */
+#define SCOPED_CHANNELLOCK(varname, chan) SCOPED_LOCK(varname, (chan), ast_channel_lock, ast_channel_unlock)
+
 #ifndef __CYGWIN__	/* temporary disabled for cygwin */
 #define pthread_mutex_t		use_ast_mutex_t_instead_of_pthread_mutex_t
 #define pthread_cond_t		use_ast_cond_t_instead_of_pthread_cond_t
diff --git a/main/config.c b/main/config.c
index 336f51e39c96560ce49d6dc6d411081ff293a90c..bf91963169d36951ba8c506877556778bc83a511 100644
--- a/main/config.c
+++ b/main/config.c
@@ -2194,15 +2194,13 @@ static void clear_config_maps(void)
 {
 	struct ast_config_map *map;
 
-	ast_mutex_lock(&config_lock);
+	SCOPED_MUTEX(lock, &config_lock);
 
 	while (config_maps) {
 		map = config_maps;
 		config_maps = config_maps->next;
 		ast_free(map);
 	}
-
-	ast_mutex_unlock(&config_lock);
 }
 
 static int append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority)
@@ -2325,7 +2323,7 @@ int ast_config_engine_register(struct ast_config_engine *new)
 {
 	struct ast_config_engine *ptr;
 
-	ast_mutex_lock(&config_lock);
+	SCOPED_MUTEX(lock, &config_lock);
 
 	if (!config_engine_list) {
 		config_engine_list = new;
@@ -2334,7 +2332,6 @@ int ast_config_engine_register(struct ast_config_engine *new)
 		ptr->next = new;
 	}
 
-	ast_mutex_unlock(&config_lock);
 	ast_log(LOG_NOTICE,"Registered Config Engine %s\n", new->name);
 
 	return 1;
@@ -2344,7 +2341,7 @@ int ast_config_engine_deregister(struct ast_config_engine *del)
 {
 	struct ast_config_engine *ptr, *last=NULL;
 
-	ast_mutex_lock(&config_lock);
+	SCOPED_MUTEX(lock, &config_lock);
 
 	for (ptr = config_engine_list; ptr; ptr=ptr->next) {
 		if (ptr == del) {
@@ -2357,25 +2354,20 @@ int ast_config_engine_deregister(struct ast_config_engine *del)
 		last = ptr;
 	}
 
-	ast_mutex_unlock(&config_lock);
-
 	return 0;
 }
 
 int ast_realtime_is_mapping_defined(const char *family)
 {
 	struct ast_config_map *map;
-	ast_mutex_lock(&config_lock);
+	SCOPED_MUTEX(lock, &config_lock);
 
 	for (map = config_maps; map; map = map->next) {
 		if (!strcasecmp(family, map->name)) {
-			ast_mutex_unlock(&config_lock);
 			return 1;
 		}
 	}
 
-	ast_mutex_unlock(&config_lock);
-
 	return 0;
 }
 
@@ -2385,7 +2377,7 @@ static struct ast_config_engine *find_engine(const char *family, int priority, c
 	struct ast_config_engine *eng, *ret = NULL;
 	struct ast_config_map *map;
 
-	ast_mutex_lock(&config_lock);
+	SCOPED_MUTEX(lock, &config_lock);
 
 	for (map = config_maps; map; map = map->next) {
 		if (!strcasecmp(family, map->name) && (priority == map->priority)) {
@@ -2405,8 +2397,6 @@ static struct ast_config_engine *find_engine(const char *family, int priority, c
 		}
 	}
 
-	ast_mutex_unlock(&config_lock);
-
 	/* if we found a mapping, but the engine is not available, then issue a warning */
 	if (map && !ret)
 		ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
@@ -3028,24 +3018,24 @@ static char *handle_cli_core_show_config_mappings(struct ast_cli_entry *e, int c
 		return NULL;
 	}
 
-	ast_mutex_lock(&config_lock);
+	{
+		SCOPED_MUTEX(lock, &config_lock);
 
-	if (!config_engine_list) {
-		ast_cli(a->fd, "No config mappings found.\n");
-	} else {
-		for (eng = config_engine_list; eng; eng = eng->next) {
-			ast_cli(a->fd, "Config Engine: %s\n", eng->name);
-			for (map = config_maps; map; map = map->next) {
-				if (!strcasecmp(map->driver, eng->name)) {
-					ast_cli(a->fd, "===> %s (db=%s, table=%s)\n", map->name, map->database,
-							map->table ? map->table : map->name);
+		if (!config_engine_list) {
+			ast_cli(a->fd, "No config mappings found.\n");
+		} else {
+			for (eng = config_engine_list; eng; eng = eng->next) {
+				ast_cli(a->fd, "Config Engine: %s\n", eng->name);
+				for (map = config_maps; map; map = map->next) {
+					if (!strcasecmp(map->driver, eng->name)) {
+						ast_cli(a->fd, "===> %s (db=%s, table=%s)\n", map->name, map->database,
+								map->table ? map->table : map->name);
+					}
 				}
 			}
 		}
 	}
 
-	ast_mutex_unlock(&config_lock);
-
 	return CLI_SUCCESS;
 }