1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <errno.h>
8 
9 #include "log_cache.h"
10 
11 #define LOG_CACHE_DBG 0
12 
13 #if LOG_CACHE_DBG
14 #include <sys/printk.h>
15 #define LOG_CACHE_PRINT(...) printk(__VA_ARGS__)
16 #define LOG_CACHE_DBG_ENTRY(str, entry) \
17 	printk(str " entry(%p) id %p\n", entry, (void *)entry->id)
18 #else
19 #define LOG_CACHE_PRINT(...)
20 #define LOG_CACHE_DBG_ENTRY(...)
21 #endif
22 
23 
log_cache_init(struct log_cache * cache,const struct log_cache_config * config)24 int log_cache_init(struct log_cache *cache, const struct log_cache_config *config)
25 {
26 	sys_slist_init(&cache->active);
27 	sys_slist_init(&cache->idle);
28 
29 	size_t entry_size = ROUND_UP(sizeof(struct log_cache_entry) + config->item_size,
30 				     sizeof(uintptr_t));
31 	uint32_t entry_cnt = config->buf_len / entry_size;
32 	struct log_cache_entry *entry = config->buf;
33 
34 	/* Ensure the cache has at least one entry */
35 	if (entry_cnt == 0) {
36 		return -EINVAL;
37 	}
38 
39 	/* Add all entries to idle list */
40 	for (uint32_t i = 0; i < entry_cnt; i++) {
41 		sys_slist_append(&cache->idle, &entry->node);
42 		entry = (struct log_cache_entry *)((uintptr_t)entry + entry_size);
43 	}
44 
45 	cache->cmp = config->cmp;
46 	cache->item_size = config->item_size;
47 	cache->hit = 0;
48 	cache->miss = 0;
49 
50 	return 0;
51 }
52 
log_cache_get(struct log_cache * cache,uintptr_t id,uint8_t ** data)53 bool log_cache_get(struct log_cache *cache, uintptr_t id, uint8_t **data)
54 {
55 	sys_snode_t *prev_node = NULL;
56 	struct log_cache_entry *entry;
57 	bool hit = false;
58 
59 	LOG_CACHE_PRINT("cache_get for id %lx\n", id);
60 	SYS_SLIST_FOR_EACH_CONTAINER(&cache->active, entry, node) {
61 		LOG_CACHE_DBG_ENTRY("checking", entry);
62 		if (cache->cmp(entry->id, id)) {
63 			cache->hit++;
64 			hit = true;
65 			break;
66 		}
67 
68 		if (&entry->node == sys_slist_peek_tail(&cache->active)) {
69 			break;
70 		}
71 		prev_node = &entry->node;
72 	}
73 
74 	if (hit) {
75 		LOG_CACHE_DBG_ENTRY("moving up", entry);
76 		sys_slist_remove(&cache->active, prev_node, &entry->node);
77 		sys_slist_prepend(&cache->active, &entry->node);
78 	} else {
79 		cache->miss++;
80 
81 		sys_snode_t *from_idle = sys_slist_get(&cache->idle);
82 
83 		if (from_idle) {
84 			entry = CONTAINER_OF(from_idle, struct log_cache_entry, node);
85 		} else {
86 			LOG_CACHE_DBG_ENTRY("removing", entry);
87 			sys_slist_remove(&cache->active, prev_node, &entry->node);
88 		}
89 	}
90 
91 	*data = entry->data;
92 	entry->id = id;
93 
94 	return hit;
95 }
96 
log_cache_put(struct log_cache * cache,uint8_t * data)97 void log_cache_put(struct log_cache *cache, uint8_t *data)
98 {
99 	struct log_cache_entry *entry = CONTAINER_OF(data, struct log_cache_entry, data[0]);
100 
101 	LOG_CACHE_DBG_ENTRY("cache_put", entry);
102 	sys_slist_prepend(&cache->active, &entry->node);
103 }
104 
log_cache_release(struct log_cache * cache,uint8_t * data)105 void log_cache_release(struct log_cache *cache, uint8_t *data)
106 {
107 	struct log_cache_entry *entry = CONTAINER_OF(data, struct log_cache_entry, data[0]);
108 
109 	LOG_CACHE_DBG_ENTRY("cache_release", entry);
110 	sys_slist_prepend(&cache->idle, &entry->node);
111 }
112