zephyr/subsys/settings/src/settings.c
Dominik Ermel dab67c35f1 settings: settings_register static table does not need mutex
It is not needed to protect static table of handlers, with mutex,
as there is no possibility that there will be anything added to the
table at runtime.

Signed-off-by: Dominik Ermel <dominik.ermel@nordicsemi.no>
2020-02-08 10:07:38 +02:00

273 lines
5.3 KiB
C

/*
* Copyright (c) 2018 Nordic Semiconductor ASA
* Copyright (c) 2015 Runtime Inc
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <kernel.h>
#include "settings/settings.h"
#include "settings_priv.h"
#include <zephyr/types.h>
#include <logging/log.h>
LOG_MODULE_REGISTER(settings, CONFIG_SETTINGS_LOG_LEVEL);
#if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS)
sys_slist_t settings_handlers;
#endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */
K_MUTEX_DEFINE(settings_lock);
void settings_store_init(void);
void settings_init(void)
{
#if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS)
sys_slist_init(&settings_handlers);
#endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */
settings_store_init();
}
#if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS)
int settings_register(struct settings_handler *handler)
{
int rc = 0;
Z_STRUCT_SECTION_FOREACH(settings_handler_static, ch) {
if (strcmp(handler->name, ch->name) == 0) {
return -EEXIST;
}
}
k_mutex_lock(&settings_lock, K_FOREVER);
struct settings_handler *ch;
SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) {
if (strcmp(handler->name, ch->name) == 0) {
rc = -EEXIST;
goto end;
}
}
sys_slist_append(&settings_handlers, &handler->node);
end:
k_mutex_unlock(&settings_lock);
return rc;
}
#endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */
int settings_name_steq(const char *name, const char *key, const char **next)
{
if (next) {
*next = NULL;
}
if ((!name) || (!key)) {
return 0;
}
/* name might come from flash directly, in flash the name would end
* with '=' or '\0' depending how storage is done. Flash reading is
* limited to what can be read
*/
while ((*key != '\0') && (*key == *name) &&
(*name != '\0') && (*name != SETTINGS_NAME_END)) {
key++;
name++;
}
if (*key != '\0') {
return 0;
}
if (*name == SETTINGS_NAME_SEPARATOR) {
if (next) {
*next = name + 1;
}
return 1;
}
if ((*name == SETTINGS_NAME_END) || (*name == '\0')) {
return 1;
}
return 0;
}
int settings_name_next(const char *name, const char **next)
{
int rc = 0;
if (next) {
*next = NULL;
}
if (!name) {
return 0;
}
/* name might come from flash directly, in flash the name would end
* with '=' or '\0' depending how storage is done. Flash reading is
* limited to what can be read
*/
while ((*name != '\0') && (*name != SETTINGS_NAME_END) &&
(*name != SETTINGS_NAME_SEPARATOR)) {
rc++;
name++;
}
if (*name == SETTINGS_NAME_SEPARATOR) {
if (next) {
*next = name + 1;
}
return rc;
}
return rc;
}
struct settings_handler_static *settings_parse_and_lookup(const char *name,
const char **next)
{
struct settings_handler_static *bestmatch;
const char *tmpnext;
bestmatch = NULL;
if (next) {
*next = NULL;
}
Z_STRUCT_SECTION_FOREACH(settings_handler_static, ch) {
if (!settings_name_steq(name, ch->name, &tmpnext)) {
continue;
}
if (!bestmatch) {
bestmatch = ch;
if (next) {
*next = tmpnext;
}
continue;
}
if (settings_name_steq(ch->name, bestmatch->name, NULL)) {
bestmatch = ch;
if (next) {
*next = tmpnext;
}
}
}
#if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS)
struct settings_handler *ch;
SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) {
if (!settings_name_steq(name, ch->name, &tmpnext)) {
continue;
}
if (!bestmatch) {
bestmatch = (struct settings_handler_static *)ch;
if (next) {
*next = tmpnext;
}
continue;
}
if (settings_name_steq(ch->name, bestmatch->name, NULL)) {
bestmatch = (struct settings_handler_static *)ch;
if (next) {
*next = tmpnext;
}
}
}
#endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */
return bestmatch;
}
int settings_call_set_handler(const char *name,
size_t len,
settings_read_cb read_cb,
void *read_cb_arg,
const struct settings_load_arg *load_arg)
{
int rc;
const char *name_key = name;
if (load_arg && load_arg->subtree &&
!settings_name_steq(name, load_arg->subtree, &name_key)) {
return 0;
}
if (load_arg && load_arg->cb) {
rc = load_arg->cb(name_key, len, read_cb, read_cb_arg,
load_arg->param);
} else {
struct settings_handler_static *ch;
ch = settings_parse_and_lookup(name, &name_key);
if (!ch) {
return 0;
}
rc = ch->h_set(name_key, len, read_cb, read_cb_arg);
if (rc != 0) {
LOG_ERR("set-value failure. key: %s error(%d)",
log_strdup(name), rc);
/* Ignoring the error */
rc = 0;
} else {
LOG_DBG("set-value OK. key: %s",
log_strdup(name));
}
}
return rc;
}
int settings_commit(void)
{
return settings_commit_subtree(NULL);
}
int settings_commit_subtree(const char *subtree)
{
int rc;
int rc2;
rc = 0;
Z_STRUCT_SECTION_FOREACH(settings_handler_static, ch) {
if (subtree && !settings_name_steq(ch->name, subtree, NULL)) {
continue;
}
if (ch->h_commit) {
rc2 = ch->h_commit();
if (!rc) {
rc = rc2;
}
}
}
#if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS)
struct settings_handler *ch;
SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) {
if (subtree && !settings_name_steq(ch->name, subtree, NULL)) {
continue;
}
if (ch->h_commit) {
rc2 = ch->h_commit();
if (!rc) {
rc = rc2;
}
}
}
#endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */
return rc;
}