From a4f73c5694a44e6948665ee54d51d8df70be8e24 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 20 Sep 2012 12:59:16 +0000 Subject: [PATCH] Fix #32579: Sequencer crash when changing render dimensions Memory limitor's queue could be affected when it's being iterated on enforcing limits -- that's because iteration could free color managed image buffers. Fixed by getting least priority element after every element was freed. Could be optimized a bit, but it anyway shouldn't be so slow due to specific of cache limiting and limit enforcing finish condition. --- intern/memutil/MEM_CacheLimiter.h | 56 ++++++++++-------------- source/blender/imbuf/intern/moviecache.c | 2 +- 2 files changed, 23 insertions(+), 35 deletions(-) diff --git a/intern/memutil/MEM_CacheLimiter.h b/intern/memutil/MEM_CacheLimiter.h index 1f1088ea118..cfff5d10e4f 100644 --- a/intern/memutil/MEM_CacheLimiter.h +++ b/intern/memutil/MEM_CacheLimiter.h @@ -123,20 +123,11 @@ public: parent->touch(this); } - void set_priority(int priority) { - this->priority = priority; - } - - int get_priority(void) { - return this->priority; - } - private: friend class MEM_CacheLimiter; T * data; int refcount; - int priority; typename std::list *, MEM_Allocator *> >::iterator me; MEM_CacheLimiter * parent; }; @@ -171,7 +162,6 @@ public: } void enforce_limits() { - MEM_CachePriorityQueue priority_queue; size_t max = MEM_CacheLimiter_get_maximum(); size_t mem_in_use, cur_size; @@ -190,12 +180,11 @@ public: return; } - priority_queue = get_priority_queue(); + while (!queue.empty() && mem_in_use > max) { + MEM_CacheElementPtr elem = get_least_priority_destroyable_element(); - while (!priority_queue.empty() && mem_in_use > max) { - MEM_CacheElementPtr elem = priority_queue.top(); - - priority_queue.pop(); + if (!elem) + break; if (getDataSize) { cur_size = getDataSize(elem->get()->get_data()); @@ -232,14 +221,6 @@ private: typedef std::list > MEM_CacheQueue; typedef typename MEM_CacheQueue::iterator iterator; - struct compare_element_priority : public std::binary_function { - bool operator()(const MEM_CacheElementPtr left_elem, const MEM_CacheElementPtr right_elem) const { - return left_elem->get_priority() > right_elem->get_priority(); - } - }; - - typedef std::priority_queue, compare_element_priority > MEM_CachePriorityQueue; - size_t total_size() { size_t size = 0; for (iterator it = queue.begin(); it != queue.end(); it++) { @@ -248,28 +229,35 @@ private: return size; } - MEM_CachePriorityQueue get_priority_queue(void) { - MEM_CachePriorityQueue priority_queue; + MEM_CacheElementPtr get_least_priority_destroyable_element(void) { + if (queue.empty()) + return NULL; + + if (!getItemPriority) + return *queue.begin(); + + MEM_CacheElementPtr best_match_elem = NULL; + int best_match_priority = 0; iterator it; int i; for (it = queue.begin(), i = 0; it != queue.end(); it++, i++) { MEM_CacheElementPtr elem = *it; - int priority; + + if (!elem->can_destroy()) + continue; /* by default 0 means higherst priority element */ - priority = -(queue.size() - i - 1); + int priority = -(queue.size() - i - 1); + priority = getItemPriority(elem->get()->get_data(), priority); - if (getItemPriority) { - priority = getItemPriority(elem->get()->get_data(), priority); + if (priority < best_match_priority || best_match_elem == NULL) { + best_match_priority = priority; + best_match_elem = elem; } - - elem->set_priority(priority); - - priority_queue.push(elem); } - return priority_queue; + return best_match_elem; } MEM_CacheQueue queue; diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c index 78a989ad48f..d5aa635f548 100644 --- a/source/blender/imbuf/intern/moviecache.c +++ b/source/blender/imbuf/intern/moviecache.c @@ -386,7 +386,7 @@ ImBuf *IMB_moviecache_get(MovieCache *cache, void *userkey) void IMB_moviecache_free(MovieCache *cache) { - PRINT("%s: create '%s' free\n", __func__, cache->name); + PRINT("%s: cache '%s' free\n", __func__, cache->name); BLI_ghash_free(cache->hash, moviecache_keyfree, moviecache_valfree);