diff --git a/include/asterisk/lock.h b/include/asterisk/lock.h index 943c7ffe61..573fc0c002 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 336f51e39c..bf91963169 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; }