zephyr/subsys/logging/log_cache.c

112 lines
2.6 KiB
C

/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include "log_cache.h"
#define LOG_CACHE_DBG 0
#if LOG_CACHE_DBG
#include <sys/printk.h>
#define LOG_CACHE_PRINT(...) printk(__VA_ARGS__)
#define LOG_CACHE_DBG_ENTRY(str, entry) \
printk(str " entry(%p) id %p\n", entry, (void *)entry->id)
#else
#define LOG_CACHE_PRINT(...)
#define LOG_CACHE_DBG_ENTRY(...)
#endif
int log_cache_init(struct log_cache *cache, const struct log_cache_config *config)
{
sys_slist_init(&cache->active);
sys_slist_init(&cache->idle);
size_t entry_size = ROUND_UP(sizeof(struct log_cache_entry) + config->item_size,
sizeof(uintptr_t));
uint32_t entry_cnt = config->buf_len / entry_size;
struct log_cache_entry *entry = config->buf;
/* Ensure the cache has at least one entry */
if (entry_cnt == 0) {
return -EINVAL;
}
/* Add all entries to idle list */
for (uint32_t i = 0; i < entry_cnt; i++) {
sys_slist_append(&cache->idle, &entry->node);
entry = (struct log_cache_entry *)((uintptr_t)entry + entry_size);
}
cache->cmp = config->cmp;
cache->item_size = config->item_size;
cache->hit = 0;
cache->miss = 0;
return 0;
}
bool log_cache_get(struct log_cache *cache, uintptr_t id, uint8_t **data)
{
sys_snode_t *prev_node = NULL;
struct log_cache_entry *entry;
bool hit = false;
LOG_CACHE_PRINT("cache_get for id %lx\n", id);
SYS_SLIST_FOR_EACH_CONTAINER(&cache->active, entry, node) {
LOG_CACHE_DBG_ENTRY("checking", entry);
if (cache->cmp(entry->id, id)) {
cache->hit++;
hit = true;
break;
}
if (&entry->node == sys_slist_peek_tail(&cache->active)) {
break;
}
prev_node = &entry->node;
}
if (hit) {
LOG_CACHE_DBG_ENTRY("moving up", entry);
sys_slist_remove(&cache->active, prev_node, &entry->node);
sys_slist_prepend(&cache->active, &entry->node);
} else {
cache->miss++;
sys_snode_t *from_idle = sys_slist_get(&cache->idle);
if (from_idle) {
entry = CONTAINER_OF(from_idle, struct log_cache_entry, node);
} else {
LOG_CACHE_DBG_ENTRY("removing", entry);
sys_slist_remove(&cache->active, prev_node, &entry->node);
}
}
*data = entry->data;
entry->id = id;
return hit;
}
void log_cache_put(struct log_cache *cache, uint8_t *data)
{
struct log_cache_entry *entry = CONTAINER_OF(data, struct log_cache_entry, data[0]);
LOG_CACHE_DBG_ENTRY("cache_put", entry);
sys_slist_prepend(&cache->active, &entry->node);
}
void log_cache_release(struct log_cache *cache, uint8_t *data)
{
struct log_cache_entry *entry = CONTAINER_OF(data, struct log_cache_entry, data[0]);
LOG_CACHE_DBG_ENTRY("cache_release", entry);
sys_slist_prepend(&cache->idle, &entry->node);
}