1 /**
2 * @file lv_cache.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_cache.h"
10 #include "../../stdlib/lv_sprintf.h"
11 #include "../lv_assert.h"
12 #include "lv_cache_entry_private.h"
13 #include "lv_cache_private.h"
14
15 /*********************
16 * DEFINES
17 *********************/
18
19 /**********************
20 * TYPEDEFS
21 **********************/
22
23 /**********************
24 * STATIC PROTOTYPES
25 **********************/
26 static void cache_drop_internal_no_lock(lv_cache_t * cache, const void * key, void * user_data);
27 static bool cache_evict_one_internal_no_lock(lv_cache_t * cache, void * user_data);
28 static lv_cache_entry_t * cache_add_internal_no_lock(lv_cache_t * cache, const void * key, void * user_data);
29
30 /**********************
31 * GLOBAL VARIABLES
32 **********************/
33
34 /**********************
35 * STATIC VARIABLES
36 **********************/
37
38 /**********************
39 * MACROS
40 **********************/
41
42 /**********************
43 * GLOBAL FUNCTIONS
44 **********************/
45
lv_cache_create(const lv_cache_class_t * cache_class,size_t node_size,size_t max_size,lv_cache_ops_t ops)46 lv_cache_t * lv_cache_create(const lv_cache_class_t * cache_class,
47 size_t node_size, size_t max_size,
48 lv_cache_ops_t ops)
49 {
50 lv_cache_t * cache = cache_class->alloc_cb();
51 LV_ASSERT_MALLOC(cache);
52
53 cache->clz = cache_class;
54 cache->node_size = node_size;
55 cache->max_size = max_size;
56 cache->size = 0;
57 cache->ops = ops;
58
59 if(cache->clz->init_cb(cache) == false) {
60 LV_LOG_ERROR("Cache init failed");
61 lv_free(cache);
62 return NULL;
63 }
64
65 lv_mutex_init(&cache->lock);
66
67 return cache;
68 }
69
lv_cache_destroy(lv_cache_t * cache,void * user_data)70 void lv_cache_destroy(lv_cache_t * cache, void * user_data)
71 {
72 LV_ASSERT_NULL(cache);
73
74 lv_mutex_lock(&cache->lock);
75 cache->clz->destroy_cb(cache, user_data);
76 lv_mutex_unlock(&cache->lock);
77 lv_mutex_delete(&cache->lock);
78 lv_free(cache);
79 }
80
lv_cache_acquire(lv_cache_t * cache,const void * key,void * user_data)81 lv_cache_entry_t * lv_cache_acquire(lv_cache_t * cache, const void * key, void * user_data)
82 {
83 LV_ASSERT_NULL(cache);
84 LV_ASSERT_NULL(key);
85
86 LV_PROFILER_CACHE_BEGIN;
87
88 lv_mutex_lock(&cache->lock);
89
90 if(cache->size == 0) {
91 lv_mutex_unlock(&cache->lock);
92
93 LV_PROFILER_CACHE_END;
94 return NULL;
95 }
96
97 lv_cache_entry_t * entry = cache->clz->get_cb(cache, key, user_data);
98 if(entry != NULL) {
99 lv_cache_entry_acquire_data(entry);
100 }
101 lv_mutex_unlock(&cache->lock);
102
103 LV_PROFILER_CACHE_END;
104 return entry;
105 }
lv_cache_release(lv_cache_t * cache,lv_cache_entry_t * entry,void * user_data)106 void lv_cache_release(lv_cache_t * cache, lv_cache_entry_t * entry, void * user_data)
107 {
108 LV_ASSERT_NULL(entry);
109
110 LV_PROFILER_CACHE_BEGIN;
111
112 lv_mutex_lock(&cache->lock);
113 lv_cache_entry_release_data(entry, user_data);
114
115 if(lv_cache_entry_get_ref(entry) == 0 && lv_cache_entry_is_invalid(entry)) {
116 cache->ops.free_cb(lv_cache_entry_get_data(entry), user_data);
117 lv_cache_entry_delete(entry);
118 }
119 lv_mutex_unlock(&cache->lock);
120
121 LV_PROFILER_CACHE_END;
122 }
lv_cache_add(lv_cache_t * cache,const void * key,void * user_data)123 lv_cache_entry_t * lv_cache_add(lv_cache_t * cache, const void * key, void * user_data)
124 {
125 LV_ASSERT_NULL(cache);
126 LV_ASSERT_NULL(key);
127
128 LV_PROFILER_CACHE_BEGIN;
129
130 lv_mutex_lock(&cache->lock);
131 if(cache->max_size == 0) {
132 lv_mutex_unlock(&cache->lock);
133
134 LV_PROFILER_CACHE_END;
135 return NULL;
136 }
137
138 lv_cache_entry_t * entry = cache_add_internal_no_lock(cache, key, user_data);
139 if(entry != NULL) {
140 lv_cache_entry_acquire_data(entry);
141 }
142 lv_mutex_unlock(&cache->lock);
143
144 LV_PROFILER_CACHE_END;
145 return entry;
146 }
lv_cache_acquire_or_create(lv_cache_t * cache,const void * key,void * user_data)147 lv_cache_entry_t * lv_cache_acquire_or_create(lv_cache_t * cache, const void * key, void * user_data)
148 {
149 LV_ASSERT_NULL(cache);
150 LV_ASSERT_NULL(key);
151
152 LV_PROFILER_CACHE_BEGIN;
153
154 lv_mutex_lock(&cache->lock);
155 lv_cache_entry_t * entry = NULL;
156
157 if(cache->size != 0) {
158 entry = cache->clz->get_cb(cache, key, user_data);
159 if(entry != NULL) {
160 lv_cache_entry_acquire_data(entry);
161 lv_mutex_unlock(&cache->lock);
162
163 LV_PROFILER_CACHE_END;
164 return entry;
165 }
166 }
167
168 if(cache->max_size == 0) {
169 lv_mutex_unlock(&cache->lock);
170
171 LV_PROFILER_CACHE_END;
172 return NULL;
173 }
174
175 entry = cache_add_internal_no_lock(cache, key, user_data);
176 if(entry == NULL) {
177 lv_mutex_unlock(&cache->lock);
178
179 LV_PROFILER_CACHE_END;
180 return NULL;
181 }
182 bool create_res = cache->ops.create_cb(lv_cache_entry_get_data(entry), user_data);
183 if(create_res == false) {
184 cache->clz->remove_cb(cache, entry, user_data);
185 lv_cache_entry_delete(entry);
186 entry = NULL;
187 }
188 else {
189 lv_cache_entry_acquire_data(entry);
190 }
191 lv_mutex_unlock(&cache->lock);
192
193 LV_PROFILER_CACHE_END;
194 return entry;
195 }
lv_cache_reserve(lv_cache_t * cache,uint32_t reserved_size,void * user_data)196 void lv_cache_reserve(lv_cache_t * cache, uint32_t reserved_size, void * user_data)
197 {
198 LV_ASSERT_NULL(cache);
199
200 LV_PROFILER_CACHE_BEGIN;
201
202 for(lv_cache_reserve_cond_res_t reserve_cond_res = cache->clz->reserve_cond_cb(cache, NULL, reserved_size, user_data);
203 reserve_cond_res == LV_CACHE_RESERVE_COND_NEED_VICTIM;
204 reserve_cond_res = cache->clz->reserve_cond_cb(cache, NULL, reserved_size, user_data))
205 cache_evict_one_internal_no_lock(cache, user_data);
206
207 LV_PROFILER_CACHE_END;
208 }
lv_cache_drop(lv_cache_t * cache,const void * key,void * user_data)209 void lv_cache_drop(lv_cache_t * cache, const void * key, void * user_data)
210 {
211 LV_ASSERT_NULL(cache);
212 LV_ASSERT_NULL(key);
213
214 LV_PROFILER_CACHE_BEGIN;
215
216 lv_mutex_lock(&cache->lock);
217 cache_drop_internal_no_lock(cache, key, user_data);
218 lv_mutex_unlock(&cache->lock);
219
220 LV_PROFILER_CACHE_END;
221 }
lv_cache_evict_one(lv_cache_t * cache,void * user_data)222 bool lv_cache_evict_one(lv_cache_t * cache, void * user_data)
223 {
224 LV_ASSERT_NULL(cache);
225
226 LV_PROFILER_CACHE_BEGIN;
227
228 lv_mutex_lock(&cache->lock);
229 bool res = cache_evict_one_internal_no_lock(cache, user_data);
230 lv_mutex_unlock(&cache->lock);
231
232 LV_PROFILER_CACHE_END;
233 return res;
234 }
lv_cache_drop_all(lv_cache_t * cache,void * user_data)235 void lv_cache_drop_all(lv_cache_t * cache, void * user_data)
236 {
237 LV_ASSERT_NULL(cache);
238
239 LV_PROFILER_CACHE_BEGIN;
240
241 lv_mutex_lock(&cache->lock);
242 cache->clz->drop_all_cb(cache, user_data);
243 lv_mutex_unlock(&cache->lock);
244
245 LV_PROFILER_CACHE_END;
246 }
247
lv_cache_set_max_size(lv_cache_t * cache,size_t max_size,void * user_data)248 void lv_cache_set_max_size(lv_cache_t * cache, size_t max_size, void * user_data)
249 {
250 LV_UNUSED(user_data);
251 cache->max_size = max_size;
252 }
lv_cache_get_max_size(lv_cache_t * cache,void * user_data)253 size_t lv_cache_get_max_size(lv_cache_t * cache, void * user_data)
254 {
255 LV_UNUSED(user_data);
256 return cache->max_size;
257 }
lv_cache_get_size(lv_cache_t * cache,void * user_data)258 size_t lv_cache_get_size(lv_cache_t * cache, void * user_data)
259 {
260 LV_UNUSED(user_data);
261 return cache->size;
262 }
lv_cache_get_free_size(lv_cache_t * cache,void * user_data)263 size_t lv_cache_get_free_size(lv_cache_t * cache, void * user_data)
264 {
265 LV_UNUSED(user_data);
266 return cache->max_size - cache->size;
267 }
lv_cache_is_enabled(lv_cache_t * cache)268 bool lv_cache_is_enabled(lv_cache_t * cache)
269 {
270 return cache->max_size > 0;
271 }
lv_cache_set_compare_cb(lv_cache_t * cache,lv_cache_compare_cb_t compare_cb,void * user_data)272 void lv_cache_set_compare_cb(lv_cache_t * cache, lv_cache_compare_cb_t compare_cb, void * user_data)
273 {
274 LV_UNUSED(user_data);
275 cache->ops.compare_cb = compare_cb;
276 }
lv_cache_set_create_cb(lv_cache_t * cache,lv_cache_create_cb_t alloc_cb,void * user_data)277 void lv_cache_set_create_cb(lv_cache_t * cache, lv_cache_create_cb_t alloc_cb, void * user_data)
278 {
279 LV_UNUSED(user_data);
280 cache->ops.create_cb = alloc_cb;
281 }
lv_cache_set_free_cb(lv_cache_t * cache,lv_cache_free_cb_t free_cb,void * user_data)282 void lv_cache_set_free_cb(lv_cache_t * cache, lv_cache_free_cb_t free_cb, void * user_data)
283 {
284 LV_UNUSED(user_data);
285 cache->ops.free_cb = free_cb;
286 }
lv_cache_set_name(lv_cache_t * cache,const char * name)287 void lv_cache_set_name(lv_cache_t * cache, const char * name)
288 {
289 if(cache == NULL) return;
290 cache->name = name;
291 }
lv_cache_get_name(lv_cache_t * cache)292 const char * lv_cache_get_name(lv_cache_t * cache)
293 {
294 return cache->name;
295 }
296
lv_cache_iter_create(lv_cache_t * cache)297 lv_iter_t * lv_cache_iter_create(lv_cache_t * cache)
298 {
299 LV_ASSERT_NULL(cache);
300 if(cache == NULL || cache->clz->iter_create_cb == NULL) return NULL;
301 return cache->clz->iter_create_cb(cache);
302 }
303
304 /**********************
305 * STATIC FUNCTIONS
306 **********************/
307
cache_drop_internal_no_lock(lv_cache_t * cache,const void * key,void * user_data)308 static void cache_drop_internal_no_lock(lv_cache_t * cache, const void * key, void * user_data)
309 {
310 lv_cache_entry_t * entry = cache->clz->get_cb(cache, key, user_data);
311 if(entry == NULL) {
312 return;
313 }
314
315 if(lv_cache_entry_get_ref(entry) == 0) {
316 cache->clz->remove_cb(cache, entry, user_data);
317 cache->ops.free_cb(lv_cache_entry_get_data(entry), user_data);
318 lv_cache_entry_delete(entry);
319 }
320 else {
321 lv_cache_entry_set_invalid(entry, true);
322 cache->clz->remove_cb(cache, entry, user_data);
323 }
324 }
325
cache_evict_one_internal_no_lock(lv_cache_t * cache,void * user_data)326 static bool cache_evict_one_internal_no_lock(lv_cache_t * cache, void * user_data)
327 {
328 lv_cache_entry_t * victim = cache->clz->get_victim_cb(cache, user_data);
329
330 if(victim == NULL) {
331 LV_LOG_ERROR("No victim found");
332 return false;
333 }
334
335 cache->clz->remove_cb(cache, victim, user_data);
336 cache->ops.free_cb(lv_cache_entry_get_data(victim), user_data);
337 lv_cache_entry_delete(victim);
338 return true;
339 }
340
cache_add_internal_no_lock(lv_cache_t * cache,const void * key,void * user_data)341 static lv_cache_entry_t * cache_add_internal_no_lock(lv_cache_t * cache, const void * key, void * user_data)
342 {
343 lv_cache_reserve_cond_res_t reserve_cond_res = cache->clz->reserve_cond_cb(cache, key, 0, user_data);
344 if(reserve_cond_res == LV_CACHE_RESERVE_COND_TOO_LARGE) {
345 LV_LOG_ERROR("data %p is too large that exceeds max size (%" LV_PRIu32 ")", key, cache->max_size);
346 return NULL;
347 }
348
349 for(; reserve_cond_res == LV_CACHE_RESERVE_COND_NEED_VICTIM;
350 reserve_cond_res = cache->clz->reserve_cond_cb(cache, key, 0, user_data))
351 if(cache_evict_one_internal_no_lock(cache, user_data) == false)
352 return NULL;
353
354 lv_cache_entry_t * entry = cache->clz->add_cb(cache, key, user_data);
355
356 return entry;
357 }
358