blob: a3ad43ac1fb44b1d4d5ae7dd190c0f56650dcb7a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <string.h>
#include "os/os.h"
#include "log/log.h"
#include "log/log_fcb_slot1.h"
#if MYNEWT_VAL(LOG_FCB_SLOT1)
static struct os_mutex g_log_slot1_mutex;
static bool g_slot1_locked;
/*
* This is convenience macro to call proper log handler depending on current log
* state.
*/
#define LOG_FCB_SLOT1_CALL(_log, _name, ...) \
({ \
int ret; \
struct log_fcb_slot1 *s1; \
s1 = _log->l_arg; \
os_mutex_pend(&s1->mutex, OS_TIMEOUT_NEVER); \
if (s1->l_current) { \
ret = s1->l_current->l_log->_name(s1->l_current, \
## __VA_ARGS__); \
} else { \
ret = -OS_EBUSY; \
} \
os_mutex_release(&s1->mutex); \
ret; \
})
static int
log_fcb_slot1_append(struct log *log, void *buf, int len)
{
return LOG_FCB_SLOT1_CALL(log, log_append, buf, len);
}
static int
log_fcb_slot1_append_body(struct log *log, const struct log_entry_hdr *hdr,
const void *body, int body_len)
{
return LOG_FCB_SLOT1_CALL(log, log_append_body, hdr, body, body_len);
}
static int
log_fcb_slot1_append_mbuf(struct log *log, const struct os_mbuf *om)
{
return LOG_FCB_SLOT1_CALL(log, log_append_mbuf, om);
}
static int
log_fcb_slot1_append_mbuf_body(struct log *log,
const struct log_entry_hdr *hdr,
const struct os_mbuf *om)
{
return LOG_FCB_SLOT1_CALL(log, log_append_mbuf_body, hdr, om);
}
static int
log_fcb_slot1_read(struct log *log, void *dptr, void *buf, uint16_t offset,
uint16_t len)
{
return LOG_FCB_SLOT1_CALL(log, log_read, dptr, buf, offset, len);
}
static int
log_fcb_slot1_read_mbuf(struct log *log, void *dptr, struct os_mbuf *om,
uint16_t offset, uint16_t len)
{
return LOG_FCB_SLOT1_CALL(log, log_read_mbuf, dptr, om, offset, len);
}
static int
log_fcb_slot1_walk(struct log *log, log_walk_func_t walk_func,
struct log_offset *log_offset)
{
return LOG_FCB_SLOT1_CALL(log, log_walk, walk_func, log_offset);
}
static int
log_fcb_slot1_flush(struct log *log)
{
return LOG_FCB_SLOT1_CALL(log, log_flush);
}
static int
log_fcb_slot1_storage_info(struct log *log, struct log_storage_info *info)
{
return LOG_FCB_SLOT1_CALL(log, log_storage_info, info);
}
static int
log_fcb_slot1_set_watermark(struct log *log, uint32_t index)
{
return LOG_FCB_SLOT1_CALL(log, log_set_watermark, index);
}
static int
log_fcb_slot1_registered(struct log *log)
{
struct log_fcb_slot1 *s1 = log->l_arg;
/* l_log and l_arg are set in log_fcb_slot1_init() */
s1->l_fcb.l_name = log->l_name;
s1->l_fcb.l_level = log->l_level;
s1->l_cbmem.l_name = log->l_name;
s1->l_cbmem.l_level = log->l_level;
os_mutex_pend(&g_log_slot1_mutex, OS_TIMEOUT_NEVER);
if (!g_slot1_locked) {
s1->fcb_reinit_fn(s1->l_fcb.l_arg);
s1->l_current = &s1->l_fcb;
} else if (s1->l_cbmem.l_log) {
s1->l_current = &s1->l_cbmem;
} else {
s1->l_current = NULL;
}
if (s1->l_current && s1->l_current->l_log->log_registered) {
s1->l_current->l_log->log_registered(s1->l_current);
}
os_mutex_release(&g_log_slot1_mutex);
return 0;
}
const struct log_handler log_fcb_slot1_handler = {
.log_type = LOG_TYPE_STORAGE,
.log_read = log_fcb_slot1_read,
.log_read_mbuf = log_fcb_slot1_read_mbuf,
.log_append = log_fcb_slot1_append,
.log_append_body = log_fcb_slot1_append_body,
.log_append_mbuf = log_fcb_slot1_append_mbuf,
.log_append_mbuf_body = log_fcb_slot1_append_mbuf_body,
.log_walk = log_fcb_slot1_walk,
.log_flush = log_fcb_slot1_flush,
#if MYNEWT_VAL(LOG_STORAGE_INFO)
.log_storage_info = log_fcb_slot1_storage_info,
#endif
#if MYNEWT_VAL(LOG_STORAGE_WATERMARK)
.log_set_watermark = log_fcb_slot1_set_watermark,
#endif
.log_registered = log_fcb_slot1_registered,
};
int
log_fcb_slot1_init(struct log_fcb_slot1 *s1, struct fcb_log *fcb_arg,
struct cbmem *cbmem_arg,
log_fcb_slot1_reinit_fcb_fn fcb_reinit_fn)
{
if (!fcb_arg || !fcb_reinit_fn) {
return -1;
}
memset(s1, 0, sizeof(*s1));
s1->l_fcb.l_log = &log_fcb_handler;
s1->l_fcb.l_arg = fcb_arg;
if (cbmem_arg) {
s1->l_cbmem.l_log = &log_cbmem_handler;
s1->l_cbmem.l_arg = cbmem_arg;
}
s1->fcb_reinit_fn = fcb_reinit_fn;
return 0;
}
void
log_fcb_slot1_lock(void)
{
struct log *log = NULL;
struct log_fcb_slot1 *s1;
if (g_slot1_locked) {
return;
}
os_mutex_pend(&g_log_slot1_mutex, OS_TIMEOUT_NEVER);
/*
* When locking slot, we go through all slot1 handlers and:
* - update current handler to CBMEM
* - flush it before using
*/
while (1) {
log = log_list_get_next(log);
if (log == NULL) {
break;
}
if (log->l_log != &log_fcb_slot1_handler) {
continue;
}
s1 = log->l_arg;
os_mutex_pend(&s1->mutex, OS_TIMEOUT_NEVER);
if (s1->l_cbmem.l_log) {
s1->l_current = &s1->l_cbmem;
log_flush(s1->l_current);
} else {
s1->l_current = NULL;
}
if (s1->l_current && s1->l_current->l_log->log_registered) {
s1->l_current->l_log->log_registered(s1->l_current);
}
os_mutex_release(&s1->mutex);
}
g_slot1_locked = true;
os_mutex_release(&g_log_slot1_mutex);
}
static int
walk_copy_entry(struct log *log, struct log_offset *log_offset, void *dptr,
uint16_t len)
{
struct os_mbuf *om;
struct log *l_target;
int rc;
om = os_msys_get(len, 0);
if (!om) {
return -1;
}
rc = log_read_mbuf(log, dptr, om, 0, len);
if (rc != len) {
os_mbuf_free_chain(om);
return -1;
}
l_target = log_offset->lo_arg;
l_target->l_log->log_append_mbuf(l_target, om);
os_mbuf_free_chain(om);
return (0);
}
void
log_fcb_slot1_unlock(void)
{
struct log *log = NULL;
struct log_fcb_slot1 *s1;
struct log_offset lo;
int rc;
if (!g_slot1_locked) {
return;
}
os_mutex_pend(&g_log_slot1_mutex, OS_TIMEOUT_NEVER);
/*
* When unlocking slot, we go through all slot1 handlers and:
* - ask application to reinitialize FCB
* - copy entries from CBMEM to FCB
* - update current log handler to FCB
*/
while (1) {
log = log_list_get_next(log);
if (log == NULL) {
break;
}
if (log->l_log != &log_fcb_slot1_handler) {
continue;
}
s1 = log->l_arg;
rc = s1->fcb_reinit_fn(s1->l_fcb.l_arg);
if (rc) {
continue;
}
os_mutex_pend(&s1->mutex, OS_TIMEOUT_NEVER);
if (s1->l_current) {
lo.lo_arg = &s1->l_fcb;
lo.lo_ts = 0;
lo.lo_index = 0;
lo.lo_data_len = 0;
log_walk(s1->l_current, walk_copy_entry, &lo);
}
s1->l_current = &s1->l_fcb;
if (s1->l_current->l_log->log_registered) {
s1->l_current->l_log->log_registered(s1->l_current);
}
os_mutex_release(&s1->mutex);
}
g_slot1_locked = false;
os_mutex_release(&g_log_slot1_mutex);
}
bool
log_fcb_slot1_is_locked(void)
{
return g_slot1_locked;
}
void
log_init_slot1(void)
{
os_mutex_init(&g_log_slot1_mutex);
}
#endif