mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-05 20:20:07 +00:00
astobj2: Support using a separate object for locking.
Create ao2_alloc_with_lockobj function to support shared locking. Change-Id: Iba687eb9843922be7e481e23a32c0700ecf88a80
This commit is contained in:
@@ -368,6 +368,13 @@ enum ao2_alloc_opts {
|
|||||||
AO2_ALLOC_OPT_LOCK_NOLOCK = (2 << 0),
|
AO2_ALLOC_OPT_LOCK_NOLOCK = (2 << 0),
|
||||||
/*! The ao2 object locking option field mask. */
|
/*! The ao2 object locking option field mask. */
|
||||||
AO2_ALLOC_OPT_LOCK_MASK = (3 << 0),
|
AO2_ALLOC_OPT_LOCK_MASK = (3 << 0),
|
||||||
|
/*!
|
||||||
|
* \internal The ao2 object uses a separate object for locking.
|
||||||
|
*
|
||||||
|
* \note This option is used internally by ao2_alloc_with_lockobj and
|
||||||
|
* should never be passed directly to ao2_alloc.
|
||||||
|
*/
|
||||||
|
AO2_ALLOC_OPT_LOCK_OBJ = AO2_ALLOC_OPT_LOCK_MASK,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -408,6 +415,26 @@ void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned in
|
|||||||
|
|
||||||
/*! @} */
|
/*! @} */
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \since 14.1.0
|
||||||
|
* \brief Allocate and initialize an object with separate locking.
|
||||||
|
*
|
||||||
|
* \param data_size The sizeof() of the user-defined structure.
|
||||||
|
* \param destructor_fn The destructor function (can be NULL)
|
||||||
|
* \param lockobj A separate ao2 object that will provide locking.
|
||||||
|
* \param debug_msg An ao2 object debug tracing message.
|
||||||
|
* \return A pointer to user-data.
|
||||||
|
*
|
||||||
|
* \see \ref ao2_alloc for additional details.
|
||||||
|
*
|
||||||
|
* \note lockobj must be a valid AO2 object.
|
||||||
|
*/
|
||||||
|
#define ao2_alloc_with_lockobj(data_size, destructor_fn, lockobj, tag) \
|
||||||
|
__ao2_alloc_with_lockobj((data_size), (destructor_fn), (lockobj), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||||
|
|
||||||
|
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) attribute_warn_unused_result;
|
||||||
|
|
||||||
/*! \brief
|
/*! \brief
|
||||||
* Reference/unreference an object and return the old refcount.
|
* Reference/unreference an object and return the old refcount.
|
||||||
*
|
*
|
||||||
|
@@ -108,6 +108,17 @@ struct astobj2_rwlock {
|
|||||||
void *user_data[0];
|
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
|
#ifdef AO2_DEBUG
|
||||||
struct ao2_stats ao2;
|
struct ao2_stats ao2;
|
||||||
#endif
|
#endif
|
||||||
@@ -118,6 +129,9 @@ struct ao2_stats ao2;
|
|||||||
#define INTERNAL_OBJ_RWLOCK(user_data) \
|
#define INTERNAL_OBJ_RWLOCK(user_data) \
|
||||||
((struct astobj2_rwlock *) (((char *) (user_data)) - sizeof(struct astobj2_rwlock)))
|
((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) \
|
#define INTERNAL_OBJ(user_data) \
|
||||||
(struct astobj2 *) ((char *) user_data - sizeof(struct astobj2))
|
(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 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
|
||||||
struct astobj2_lock *obj_mutex;
|
struct astobj2_lock *obj_mutex;
|
||||||
struct astobj2_rwlock *obj_rwlock;
|
struct astobj2_rwlock *obj_rwlock;
|
||||||
|
struct astobj2_lockobj *obj_lockobj;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
if (obj == NULL) {
|
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:
|
case AO2_ALLOC_OPT_LOCK_NOLOCK:
|
||||||
/* The ao2 object has no lock. */
|
/* The ao2 object has no lock. */
|
||||||
break;
|
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:
|
default:
|
||||||
ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
|
ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
|
||||||
user_data);
|
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 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
|
||||||
struct astobj2_lock *obj_mutex;
|
struct astobj2_lock *obj_mutex;
|
||||||
struct astobj2_rwlock *obj_rwlock;
|
struct astobj2_rwlock *obj_rwlock;
|
||||||
|
struct astobj2_lockobj *obj_lockobj;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
int current_value;
|
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:
|
case AO2_ALLOC_OPT_LOCK_NOLOCK:
|
||||||
/* The ao2 object has no lock. */
|
/* The ao2 object has no lock. */
|
||||||
break;
|
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:
|
default:
|
||||||
ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
|
ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
|
||||||
user_data);
|
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 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
|
||||||
struct astobj2_lock *obj_mutex;
|
struct astobj2_lock *obj_mutex;
|
||||||
struct astobj2_rwlock *obj_rwlock;
|
struct astobj2_rwlock *obj_rwlock;
|
||||||
|
struct astobj2_lockobj *obj_lockobj;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
if (obj == NULL) {
|
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:
|
case AO2_ALLOC_OPT_LOCK_NOLOCK:
|
||||||
/* The ao2 object has no lock. */
|
/* The ao2 object has no lock. */
|
||||||
return 0;
|
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:
|
default:
|
||||||
ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
|
ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
|
||||||
user_data);
|
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 *obj = INTERNAL_OBJ(user_data);
|
||||||
struct astobj2_rwlock *obj_rwlock;
|
struct astobj2_rwlock *obj_rwlock;
|
||||||
|
struct astobj2_lockobj *obj_lockobj;
|
||||||
enum ao2_lock_req orig_lock;
|
enum ao2_lock_req orig_lock;
|
||||||
|
|
||||||
switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
|
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;
|
||||||
}
|
}
|
||||||
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:
|
default:
|
||||||
ast_log(LOG_ERROR, "Invalid lock option on ao2 object %p\n", user_data);
|
ast_log(LOG_ERROR, "Invalid lock option on ao2 object %p\n", user_data);
|
||||||
/* Fall through */
|
/* 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 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
|
||||||
struct astobj2_lock *obj_mutex;
|
struct astobj2_lock *obj_mutex;
|
||||||
struct astobj2_rwlock *obj_rwlock;
|
struct astobj2_rwlock *obj_rwlock;
|
||||||
|
struct astobj2_lockobj *obj_lockobj;
|
||||||
int current_value;
|
int current_value;
|
||||||
int ret;
|
int ret;
|
||||||
void *weakproxy = NULL;
|
void *weakproxy = NULL;
|
||||||
@@ -552,6 +587,12 @@ int __ao2_ref(void *user_data, int delta,
|
|||||||
case AO2_ALLOC_OPT_LOCK_NOLOCK:
|
case AO2_ALLOC_OPT_LOCK_NOLOCK:
|
||||||
ast_free(obj);
|
ast_free(obj);
|
||||||
break;
|
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:
|
default:
|
||||||
ast_log(__LOG_ERROR, file, line, func,
|
ast_log(__LOG_ERROR, file, line, func,
|
||||||
"Invalid lock option on ao2 object %p\n", user_data);
|
"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,
|
static void *internal_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)
|
void *lockobj, const char *tag, const char *file, int line, const char *func)
|
||||||
{
|
{
|
||||||
/* allocation */
|
/* allocation */
|
||||||
struct astobj2 *obj;
|
struct astobj2 *obj;
|
||||||
struct astobj2_lock *obj_mutex;
|
struct astobj2_lock *obj_mutex;
|
||||||
struct astobj2_rwlock *obj_rwlock;
|
struct astobj2_rwlock *obj_rwlock;
|
||||||
|
struct astobj2_lockobj *obj_lockobj;
|
||||||
|
|
||||||
switch (options & AO2_ALLOC_OPT_LOCK_MASK) {
|
switch (options & AO2_ALLOC_OPT_LOCK_MASK) {
|
||||||
case AO2_ALLOC_OPT_LOCK_MUTEX:
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
/* Invalid option value. */
|
/* Invalid option value. */
|
||||||
ast_log(__LOG_DEBUG, file, line, func, "Invalid lock option requested\n");
|
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);
|
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)
|
unsigned int ao2_options_get(void *obj)
|
||||||
{
|
{
|
||||||
struct astobj2 *orig_obj;
|
struct astobj2 *orig_obj;
|
||||||
|
Reference in New Issue
Block a user