/** * Empty the cache. Useful when there is not enough memory. */ void pb_cache_release_all_buffers(struct pb_cache *mgr) { struct list_head *curr, *next; struct pb_cache_entry *buf; pipe_mutex_lock(mgr->mutex); curr = mgr->cache.next; next = curr->next; while (curr != &mgr->cache) { buf = LIST_ENTRY(struct pb_cache_entry, curr, head); destroy_buffer_locked(buf); curr = next; next = curr->next; } pipe_mutex_unlock(mgr->mutex); }
/** * Empty the cache. Useful when there is not enough memory. */ void pb_cache_release_all_buffers(struct pb_cache *mgr) { struct list_head *curr, *next; struct pb_cache_entry *buf; unsigned i; pipe_mutex_lock(mgr->mutex); for (i = 0; i < ARRAY_SIZE(mgr->buckets); i++) { struct list_head *cache = &mgr->buckets[i]; curr = cache->next; next = curr->next; while (curr != cache) { buf = LIST_ENTRY(struct pb_cache_entry, curr, head); destroy_buffer_locked(buf); curr = next; next = curr->next; } } pipe_mutex_unlock(mgr->mutex); }
/** * Free as many cache buffers from the list head as possible. */ static void release_expired_buffers_locked(struct list_head *cache) { struct list_head *curr, *next; struct pb_cache_entry *entry; int64_t now; now = os_time_get(); curr = cache->next; next = curr->next; while (curr != cache) { entry = LIST_ENTRY(struct pb_cache_entry, curr, head); if (!os_time_timeout(entry->start, entry->end, now)) break; destroy_buffer_locked(entry); curr = next; next = curr->next; } }
/** * Find a compatible buffer in the cache, return it, and remove it * from the cache. */ struct pb_buffer * pb_cache_reclaim_buffer(struct pb_cache *mgr, pb_size size, unsigned alignment, unsigned usage, unsigned bucket_index) { struct pb_cache_entry *entry; struct pb_cache_entry *cur_entry; struct list_head *cur, *next; int64_t now; int ret = 0; struct list_head *cache = &mgr->buckets[bucket_index]; pipe_mutex_lock(mgr->mutex); entry = NULL; cur = cache->next; next = cur->next; /* search in the expired buffers, freeing them in the process */ now = os_time_get(); while (cur != cache) { cur_entry = LIST_ENTRY(struct pb_cache_entry, cur, head); if (!entry && (ret = pb_cache_is_buffer_compat(cur_entry, size, alignment, usage) > 0)) entry = cur_entry; else if (os_time_timeout(cur_entry->start, cur_entry->end, now)) destroy_buffer_locked(cur_entry); else /* This buffer (and all hereafter) are still hot in cache */ break; /* the buffer is busy (and probably all remaining ones too) */ if (ret == -1) break; cur = next; next = cur->next; } /* keep searching in the hot buffers */ if (!entry && ret != -1) { while (cur != cache) { cur_entry = LIST_ENTRY(struct pb_cache_entry, cur, head); ret = pb_cache_is_buffer_compat(cur_entry, size, alignment, usage); if (ret > 0) { entry = cur_entry; break; } if (ret == -1) break; /* no need to check the timeout here */ cur = next; next = cur->next; } } /* found a compatible buffer, return it */ if (entry) { struct pb_buffer *buf = entry->buffer; mgr->cache_size -= buf->size; LIST_DEL(&entry->head); --mgr->num_buffers; pipe_mutex_unlock(mgr->mutex); /* Increase refcount */ pipe_reference_init(&buf->reference, 1); return buf; } pipe_mutex_unlock(mgr->mutex); return NULL; }