diff options
-rw-r--r-- | include/asterisk/linkedlists.h | 25 | ||||
-rw-r--r-- | include/asterisk/lock.h | 71 | ||||
-rw-r--r-- | main/manager.c | 23 |
3 files changed, 113 insertions, 6 deletions
diff --git a/include/asterisk/linkedlists.h b/include/asterisk/linkedlists.h index 1ce7ee2bd..3c89e7117 100644 --- a/include/asterisk/linkedlists.h +++ b/include/asterisk/linkedlists.h @@ -52,6 +52,18 @@ ast_rwlock_wrlock(&(head)->lock) /*! + \brief Write locks a list, with timeout. + \param head This is a pointer to the list head structure + \param tv Pointer to a timeval structure + + This macro attempts to place an exclusive write lock in the + list head structure pointed to by head. + \retval 0 on success + \retval non-zero on failure +*/ +#define AST_RWLIST_TIMEDWRLOCK(head,tv) ast_rwlock_timedwrlock(&(head)->lock, tv) + +/*! \brief Read locks a list. \param head This is a pointer to the list head structure @@ -64,6 +76,19 @@ ast_rwlock_rdlock(&(head)->lock) /*! + \brief Read locks a list, with timeout. + \param head This is a pointer to the list head structure + \param tv Pointer to a timeval structure + + This macro attempts to place a read lock in the + list head structure pointed to by head. + \retval 0 on success + \retval non-zero on failure +*/ +#define AST_RWLIST_TIMEDRDLOCK(head,tv) \ + ast_rwlock_timedrdlock(&(head)->lock, tv) + +/*! \brief Locks a list, without blocking if the list is locked. \param head This is a pointer to the list head structure diff --git a/include/asterisk/lock.h b/include/asterisk/lock.h index d6313bbe6..757371ebd 100644 --- a/include/asterisk/lock.h +++ b/include/asterisk/lock.h @@ -883,6 +883,8 @@ typedef pthread_rwlock_t ast_rwlock_t; #define ast_rwlock_wrlock(a) _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__) #define ast_rwlock_tryrdlock(a) _ast_rwlock_tryrdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__) #define ast_rwlock_trywrlock(a) _ast_rwlock_trywrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__) +#define ast_rwlock_timedrdlock(a,b) _ast_rwlock_timedrdlock(a, # a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__) +#define ast_rwlock_timedwrlock(a,b) _ast_rwlock_timedwrlock(a, # a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__) static inline int __ast_rwlock_init(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock) @@ -1017,6 +1019,65 @@ static inline int _ast_rwlock_wrlock(ast_rwlock_t *lock, const char *name, return res; } +static inline int _ast_rwlock_timedrdlock(ast_rwlock_t *lock, const char *name, + struct timeval *abs_timeout, const char *file, int line, const char *func) +{ + int res; +#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS + int canlog = strcmp(file, "logger.c"); + + if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) { + /* Don't warn abount uninitialized lock. + * Simple try to initialize it. + * May be not needed in linux system. + */ + res = __ast_rwlock_init(file, line, func, name, lock); + if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) { + __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n", + file, line, func, name); + return res; + } + } +#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ + + ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock); + res = pthread_rwlock_timedrdlock(lock, abs_timeout); + if (!res) + ast_mark_lock_acquired(lock); + else + ast_remove_lock_info(lock); + return res; +} + +static inline int _ast_rwlock_timedwrlock(ast_rwlock_t *lock, const char *name, + struct timeval *abs_timeout, const char *file, int line, const char *func) +{ + int res; +#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS + int canlog = strcmp(file, "logger.c"); + + if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) { + /* Don't warn abount uninitialized lock. + * Simple try to initialize it. + * May be not needed in linux system. + */ + res = __ast_rwlock_init(file, line, func, name, lock); + if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) { + __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n", + file, line, func, name); + return res; + } + } +#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ + + ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock); + res = pthread_rwlock_timedwrlock(lock, abs_timeout); + if (!res) + ast_mark_lock_acquired(lock); + else + ast_remove_lock_info(lock); + return res; +} static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *lock, const char *name, const char *file, int line, const char *func) @@ -1122,6 +1183,11 @@ static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock) return pthread_rwlock_rdlock(prwlock); } +static inline int ast_rwlock_timedrdlock(ast_rwlock_t *prwlock, const struct timespec *abs_timeout) +{ + return pthread_rwlock_timedrdlock(prwlock, abs_timeout); +} + static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock) { return pthread_rwlock_tryrdlock(prwlock); @@ -1132,6 +1198,11 @@ static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock) return pthread_rwlock_wrlock(prwlock); } +static inline int ast_rwlock_timedwrlock(ast_rwlock_t *prwlock, const struct timespec *abs_timeout) +{ + return pthread_rwlock_timedwrlock(prwlock, abs_timeout); +} + static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock) { return pthread_rwlock_trywrlock(prwlock); diff --git a/main/manager.c b/main/manager.c index e503981fa..f8c96f449 100644 --- a/main/manager.c +++ b/main/manager.c @@ -3140,8 +3140,12 @@ int __manager_event(int category, const char *event, int ast_manager_unregister(char *action) { struct manager_action *cur; + struct timespec tv = { 5, }; - AST_RWLIST_WRLOCK(&actions); + if (AST_RWLIST_TIMEDWRLOCK(&actions, &tv)) { + ast_log(LOG_ERROR, "Could not obtain lock on manager list\n"); + return -1; + } AST_RWLIST_TRAVERSE_SAFE_BEGIN(&actions, cur, list) { if (!strcasecmp(action, cur->action)) { AST_RWLIST_REMOVE_CURRENT(list); @@ -3150,7 +3154,7 @@ int ast_manager_unregister(char *action) break; } } - AST_RWLIST_TRAVERSE_SAFE_END; + AST_RWLIST_TRAVERSE_SAFE_END AST_RWLIST_UNLOCK(&actions); return 0; @@ -3169,8 +3173,12 @@ static int manager_state_cb(char *context, char *exten, int state, void *data) static int ast_manager_register_struct(struct manager_action *act) { struct manager_action *cur, *prev = NULL; + struct timespec tv = { 5, }; - AST_RWLIST_WRLOCK(&actions); + if (AST_RWLIST_TIMEDWRLOCK(&actions, &tv)) { + ast_log(LOG_ERROR, "Could not obtain lock on manager list\n"); + return -1; + } AST_RWLIST_TRAVERSE(&actions, cur, list) { int ret = strcasecmp(cur->action, act->action); if (ret == 0) { @@ -3183,8 +3191,8 @@ static int ast_manager_register_struct(struct manager_action *act) break; } } - - if (prev) + + if (prev) AST_RWLIST_INSERT_AFTER(&actions, prev, act, list); else AST_RWLIST_INSERT_HEAD(&actions, act, list); @@ -3211,7 +3219,10 @@ int ast_manager_register2(const char *action, int auth, int (*func)(struct manse cur->synopsis = synopsis; cur->description = description; - ast_manager_register_struct(cur); + if (ast_manager_register_struct(cur)) { + ast_free(cur); + return -1; + } return 0; } |