[asterisk-commits] mmichelson: trunk r371582 - in /trunk: include/asterisk/lock.h main/config.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Aug 21 14:04:36 CDT 2012


Author: mmichelson
Date: Tue Aug 21 14:04:32 2012
New Revision: 371582

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=371582
Log:
Add scoped locks to Asterisk.

With the SCOPED_LOCK macro, you can create a variable
that locks a specific lock and unlocks the lock when the
variable goes out of scope. This is useful for situations
where many breaks, continues, returns, or other interruptions
would require separate unlock statements. With a scoped lock,
these aren't necessary.

There are specializations for mutexes, read locks, write locks,
ao2 locks, ao2 read locks, ao2 write locks, and channel locks.
Each of these is a SCOPED_LOCK at heart though.

Review: https://reviewboard.asterisk.org/r/2060


Modified:
    trunk/include/asterisk/lock.h
    trunk/main/config.c

Modified: trunk/include/asterisk/lock.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/lock.h?view=diff&rev=371582&r1=371581&r2=371582
==============================================================================
--- trunk/include/asterisk/lock.h (original)
+++ trunk/include/asterisk/lock.h Tue Aug 21 14:04:32 2012
@@ -549,6 +549,82 @@
 #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

Modified: trunk/main/config.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/config.c?view=diff&rev=371582&r1=371581&r2=371582
==============================================================================
--- trunk/main/config.c (original)
+++ trunk/main/config.c Tue Aug 21 14:04:32 2012
@@ -2194,15 +2194,13 @@
 {
 	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 @@
 {
 	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 @@
 		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 @@
 {
 	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,24 +2354,19 @@
 		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 @@
 	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)) {
@@ -2404,8 +2396,6 @@
 				ret = eng;
 		}
 	}
-
-	ast_mutex_unlock(&config_lock);
 
 	/* if we found a mapping, but the engine is not available, then issue a warning */
 	if (map && !ret)
@@ -3028,23 +3018,23 @@
 		return NULL;
 	}
 
-	ast_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);
-				}
-			}
-		}
-	}
-
-	ast_mutex_unlock(&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);
+					}
+				}
+			}
+		}
+	}
 
 	return CLI_SUCCESS;
 }




More information about the asterisk-commits mailing list