mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-15 06:18:38 +00:00
Merge "res_sorcery_memory_cache.c: Fix deadlock with scheduler." into 13
This commit is contained in:
@@ -122,6 +122,8 @@ struct sorcery_memory_cache {
|
|||||||
struct ast_heap *object_heap;
|
struct ast_heap *object_heap;
|
||||||
/*! \brief Scheduler item for expiring oldest object. */
|
/*! \brief Scheduler item for expiring oldest object. */
|
||||||
int expire_id;
|
int expire_id;
|
||||||
|
/*! TRUE if trying to stop the oldest object expiration scheduler item. */
|
||||||
|
unsigned int del_expire:1;
|
||||||
#ifdef TEST_FRAMEWORK
|
#ifdef TEST_FRAMEWORK
|
||||||
/*! \brief Variable used to indicate we should notify a test when we reach empty */
|
/*! \brief Variable used to indicate we should notify a test when we reach empty */
|
||||||
unsigned int cache_notify;
|
unsigned int cache_notify;
|
||||||
@@ -441,7 +443,21 @@ static int expire_objects_from_cache(const void *data)
|
|||||||
struct sorcery_memory_cache *cache = (struct sorcery_memory_cache *)data;
|
struct sorcery_memory_cache *cache = (struct sorcery_memory_cache *)data;
|
||||||
struct sorcery_memory_cached_object *cached;
|
struct sorcery_memory_cached_object *cached;
|
||||||
|
|
||||||
ao2_wrlock(cache->objects);
|
/*
|
||||||
|
* We need to do deadlock avoidance between a non-scheduler thread
|
||||||
|
* blocking when trying to delete the scheduled entry for this
|
||||||
|
* callback because the scheduler thread is running this callback
|
||||||
|
* and this callback waiting for the cache->objects container lock
|
||||||
|
* that the blocked non-scheduler thread already holds.
|
||||||
|
*/
|
||||||
|
while (ao2_trywrlock(cache->objects)) {
|
||||||
|
if (cache->del_expire) {
|
||||||
|
cache->expire_id = -1;
|
||||||
|
ao2_ref(cache, -1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
sched_yield();
|
||||||
|
}
|
||||||
|
|
||||||
cache->expire_id = -1;
|
cache->expire_id = -1;
|
||||||
|
|
||||||
@@ -486,7 +502,9 @@ static void remove_all_from_cache(struct sorcery_memory_cache *cache)
|
|||||||
ao2_callback(cache->objects, OBJ_UNLINK | OBJ_NOLOCK | OBJ_NODATA | OBJ_MULTIPLE,
|
ao2_callback(cache->objects, OBJ_UNLINK | OBJ_NOLOCK | OBJ_NODATA | OBJ_MULTIPLE,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
|
||||||
|
cache->del_expire = 1;
|
||||||
AST_SCHED_DEL_UNREF(sched, cache->expire_id, ao2_ref(cache, -1));
|
AST_SCHED_DEL_UNREF(sched, cache->expire_id, ao2_ref(cache, -1));
|
||||||
|
cache->del_expire = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -579,18 +597,9 @@ static int schedule_cache_expiration(struct sorcery_memory_cache *cache)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cache->expire_id != -1) {
|
cache->del_expire = 1;
|
||||||
/* If we can't unschedule this expiration then it is currently attempting to run,
|
AST_SCHED_DEL_UNREF(sched, cache->expire_id, ao2_ref(cache, -1));
|
||||||
* so let it run - it just means that it'll be the one scheduling instead of us.
|
cache->del_expire = 0;
|
||||||
*/
|
|
||||||
if (ast_sched_del(sched, cache->expire_id)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Since it successfully cancelled we need to drop the ref to the cache it had */
|
|
||||||
ao2_ref(cache, -1);
|
|
||||||
cache->expire_id = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cached = ast_heap_peek(cache->object_heap, 1);
|
cached = ast_heap_peek(cache->object_heap, 1);
|
||||||
if (!cached) {
|
if (!cached) {
|
||||||
|
|||||||
Reference in New Issue
Block a user