mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-02 20:08:17 +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;
|
||||
/*! \brief Scheduler item for expiring oldest object. */
|
||||
int expire_id;
|
||||
/*! TRUE if trying to stop the oldest object expiration scheduler item. */
|
||||
unsigned int del_expire:1;
|
||||
#ifdef TEST_FRAMEWORK
|
||||
/*! \brief Variable used to indicate we should notify a test when we reach empty */
|
||||
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_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;
|
||||
|
||||
@@ -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,
|
||||
NULL, NULL);
|
||||
|
||||
cache->del_expire = 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;
|
||||
}
|
||||
|
||||
if (cache->expire_id != -1) {
|
||||
/* If we can't unschedule this expiration then it is currently attempting to run,
|
||||
* so let it run - it just means that it'll be the one scheduling instead of us.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
cache->del_expire = 1;
|
||||
AST_SCHED_DEL_UNREF(sched, cache->expire_id, ao2_ref(cache, -1));
|
||||
cache->del_expire = 0;
|
||||
|
||||
cached = ast_heap_peek(cache->object_heap, 1);
|
||||
if (!cached) {
|
||||
|
||||
Reference in New Issue
Block a user