From 0c5b6e9ff559dcb20d9315154d4bd6a2ea5aa6a9 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Fri, 26 Aug 2016 14:18:10 -0400 Subject: astobj2: Support using a separate object for locking. Create ao2_alloc_with_lockobj function to support shared locking. Change-Id: Iba687eb9843922be7e481e23a32c0700ecf88a80 --- main/astobj2.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 2 deletions(-) (limited to 'main') diff --git a/main/astobj2.c b/main/astobj2.c index 5c92f263f..604e6a1ae 100644 --- a/main/astobj2.c +++ b/main/astobj2.c @@ -108,6 +108,17 @@ struct astobj2_rwlock { void *user_data[0]; }; +struct ao2_lockobj_priv { + void *lock; +}; + +/* AstObj2 with locking provided by a separate object. */ +struct astobj2_lockobj { + struct ao2_lockobj_priv lockobj; + struct __priv_data priv_data; + void *user_data[0]; +}; + #ifdef AO2_DEBUG struct ao2_stats ao2; #endif @@ -118,6 +129,9 @@ struct ao2_stats ao2; #define INTERNAL_OBJ_RWLOCK(user_data) \ ((struct astobj2_rwlock *) (((char *) (user_data)) - sizeof(struct astobj2_rwlock))) +#define INTERNAL_OBJ_LOCKOBJ(user_data) \ + ((struct astobj2_lockobj *) (((char *) (user_data)) - sizeof(struct astobj2_lockobj))) + #define INTERNAL_OBJ(user_data) \ (struct astobj2 *) ((char *) user_data - sizeof(struct astobj2)) @@ -187,6 +201,7 @@ int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, co struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func); struct astobj2_lock *obj_mutex; struct astobj2_rwlock *obj_rwlock; + struct astobj2_lockobj *obj_lockobj; int res = 0; if (obj == NULL) { @@ -231,6 +246,10 @@ int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, co case AO2_ALLOC_OPT_LOCK_NOLOCK: /* The ao2 object has no lock. */ break; + case AO2_ALLOC_OPT_LOCK_OBJ: + obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data); + res = __ao2_lock(obj_lockobj->lockobj.lock, lock_how, file, func, line, var); + break; default: ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n", user_data); @@ -245,6 +264,7 @@ int __ao2_unlock(void *user_data, const char *file, const char *func, int line, struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func); struct astobj2_lock *obj_mutex; struct astobj2_rwlock *obj_rwlock; + struct astobj2_lockobj *obj_lockobj; int res = 0; int current_value; @@ -281,6 +301,10 @@ int __ao2_unlock(void *user_data, const char *file, const char *func, int line, case AO2_ALLOC_OPT_LOCK_NOLOCK: /* The ao2 object has no lock. */ break; + case AO2_ALLOC_OPT_LOCK_OBJ: + obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data); + res = __ao2_unlock(obj_lockobj->lockobj.lock, file, func, line, var); + break; default: ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n", user_data); @@ -295,6 +319,7 @@ int __ao2_trylock(void *user_data, enum ao2_lock_req lock_how, const char *file, struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func); struct astobj2_lock *obj_mutex; struct astobj2_rwlock *obj_rwlock; + struct astobj2_lockobj *obj_lockobj; int res = 0; if (obj == NULL) { @@ -339,6 +364,10 @@ int __ao2_trylock(void *user_data, enum ao2_lock_req lock_how, const char *file, case AO2_ALLOC_OPT_LOCK_NOLOCK: /* The ao2 object has no lock. */ return 0; + case AO2_ALLOC_OPT_LOCK_OBJ: + obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data); + res = __ao2_trylock(obj_lockobj->lockobj.lock, lock_how, file, func, line, var); + break; default: ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n", user_data); @@ -370,6 +399,7 @@ enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int { struct astobj2 *obj = INTERNAL_OBJ(user_data); struct astobj2_rwlock *obj_rwlock; + struct astobj2_lockobj *obj_lockobj; enum ao2_lock_req orig_lock; switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) { @@ -400,6 +430,10 @@ enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int break; } break; + case AO2_ALLOC_OPT_LOCK_OBJ: + obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data); + orig_lock = __adjust_lock(obj_lockobj->lockobj.lock, lock_how, keep_stronger); + break; default: ast_log(LOG_ERROR, "Invalid lock option on ao2 object %p\n", user_data); /* Fall through */ @@ -441,6 +475,7 @@ int __ao2_ref(void *user_data, int delta, struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func); struct astobj2_lock *obj_mutex; struct astobj2_rwlock *obj_rwlock; + struct astobj2_lockobj *obj_lockobj; int current_value; int ret; void *weakproxy = NULL; @@ -552,6 +587,12 @@ int __ao2_ref(void *user_data, int delta, case AO2_ALLOC_OPT_LOCK_NOLOCK: ast_free(obj); break; + case AO2_ALLOC_OPT_LOCK_OBJ: + obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data); + ao2_t_ref(obj_lockobj->lockobj.lock, -1, "release lockobj"); + + ast_free(obj_lockobj); + break; default: ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n", user_data); @@ -581,13 +622,14 @@ void __ao2_cleanup(void *obj) } } -void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, - const char *tag, const char *file, int line, const char *func) +static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, + void *lockobj, const char *tag, const char *file, int line, const char *func) { /* allocation */ struct astobj2 *obj; struct astobj2_lock *obj_mutex; struct astobj2_rwlock *obj_rwlock; + struct astobj2_lockobj *obj_lockobj; switch (options & AO2_ALLOC_OPT_LOCK_MASK) { case AO2_ALLOC_OPT_LOCK_MUTEX: @@ -614,6 +656,22 @@ void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned in return NULL; } break; + case AO2_ALLOC_OPT_LOCK_OBJ: + lockobj = ao2_t_bump(lockobj, "set lockobj"); + if (!lockobj) { + ast_log(__LOG_ERROR, file, line, func, "AO2_ALLOC_OPT_LOCK_OBJ requires a non-NULL lockobj.\n"); + return NULL; + } + + obj_lockobj = __ast_calloc(1, sizeof(*obj_lockobj) + data_size, file, line, func); + if (obj_lockobj == NULL) { + ao2_t_ref(lockobj, -1, "release lockobj for failed alloc"); + return NULL; + } + + obj_lockobj->lockobj.lock = lockobj; + obj = (struct astobj2 *) &obj_lockobj->priv_data; + break; default: /* Invalid option value. */ ast_log(__LOG_DEBUG, file, line, func, "Invalid lock option requested\n"); @@ -643,6 +701,19 @@ void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned in return EXTERNAL_OBJ(obj); } +void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, + const char *tag, const char *file, int line, const char *func) +{ + return internal_ao2_alloc(data_size, destructor_fn, options, NULL, tag, file, line, func); +} + +void *__ao2_alloc_with_lockobj(size_t data_size, ao2_destructor_fn destructor_fn, void *lockobj, + const char *tag, const char *file, int line, const char *func) +{ + return internal_ao2_alloc(data_size, destructor_fn, AO2_ALLOC_OPT_LOCK_OBJ, lockobj, + tag, file, line, func); +} + unsigned int ao2_options_get(void *obj) { struct astobj2 *orig_obj; -- cgit v1.2.3