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