blob: 84d161f8c95c658d0fa1e89285b474f25f364846 [file] [log] [blame]
/**
* Copyright (c) 2015 Runtime Inc.
*
* Licensed 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 <os/os.h>
#include <string.h>
#include "util/cbmem.h"
int
cbmem_init(struct cbmem *cbmem, void *buf, uint32_t buf_len)
{
os_mutex_init(&cbmem->c_lock);
memset(cbmem, 0, sizeof(*cbmem));
cbmem->c_buf = buf;
cbmem->c_buf_end = buf + buf_len;
return (0);
}
int
cbmem_lock_acquire(struct cbmem *cbmem)
{
int rc;
if (!os_started()) {
return (0);
}
rc = os_mutex_pend(&cbmem->c_lock, OS_WAIT_FOREVER);
if (rc != 0) {
goto err;
}
return (0);
err:
return (rc);
}
int
cbmem_lock_release(struct cbmem *cbmem)
{
int rc;
if (!os_started()) {
return (0);
}
rc = os_mutex_release(&cbmem->c_lock);
if (rc != 0) {
goto err;
}
return (0);
err:
return (rc);
}
int
cbmem_append(struct cbmem *cbmem, void *data, uint16_t len)
{
struct cbmem_entry_hdr *dst;
uint8_t *start;
uint8_t *end;
int rc;
rc = cbmem_lock_acquire(cbmem);
if (rc != 0) {
goto err;
}
if (cbmem->c_entry_end) {
dst = CBMEM_ENTRY_NEXT(cbmem->c_entry_end);
} else {
dst = (struct cbmem_entry_hdr *) cbmem->c_buf;
}
end = (uint8_t *) dst + len;
/* If this item would take us past the end of this buffer, then adjust
* the item to the beginning of the buffer.
*/
if (end > cbmem->c_buf_end) {
cbmem->c_buf_cur_end = (uint8_t *) dst;
dst = (struct cbmem_entry_hdr *) cbmem->c_buf;
end = (uint8_t *) dst + len;
if ((uint8_t *) cbmem->c_entry_start >= cbmem->c_buf_cur_end) {
cbmem->c_entry_start = (struct cbmem_entry_hdr *) cbmem->c_buf;
}
}
/* If the destination is prior to the start, and would overrwrite the
* start of the buffer, move start forward until you don't overwrite it
* anymore.
*/
start = (uint8_t *) cbmem->c_entry_start;
if (start && (uint8_t *) dst < start + CBMEM_ENTRY_SIZE(start) &&
end > start) {
while (start < end) {
start = (uint8_t *) CBMEM_ENTRY_NEXT(start);
if (start == cbmem->c_buf_cur_end) {
start = cbmem->c_buf;
break;
}
}
cbmem->c_entry_start = (struct cbmem_entry_hdr *) start;
}
/* Copy the entry into the log
*/
dst->ceh_len = len;
memcpy((uint8_t *) dst + sizeof(*dst), data, len);
cbmem->c_entry_end = dst;
if (!cbmem->c_entry_start) {
cbmem->c_entry_start = dst;
}
rc = cbmem_lock_release(cbmem);
if (rc != 0) {
goto err;
}
return (0);
err:
return (-1);
}
void
cbmem_iter_start(struct cbmem *cbmem, struct cbmem_iter *iter)
{
iter->ci_start = cbmem->c_entry_start;
iter->ci_cur = cbmem->c_entry_start;
iter->ci_end = cbmem->c_entry_end;
}
struct cbmem_entry_hdr *
cbmem_iter_next(struct cbmem *cbmem, struct cbmem_iter *iter)
{
struct cbmem_entry_hdr *hdr;
if (iter->ci_start > iter->ci_end) {
hdr = iter->ci_cur;
iter->ci_cur = CBMEM_ENTRY_NEXT(iter->ci_cur);
if ((uint8_t *) iter->ci_cur == cbmem->c_buf_cur_end) {
iter->ci_cur = (struct cbmem_entry_hdr *) cbmem->c_buf;
iter->ci_start = (struct cbmem_entry_hdr *) cbmem->c_buf;
}
} else {
hdr = iter->ci_cur;
if (hdr == CBMEM_ENTRY_NEXT(iter->ci_end)) {
hdr = NULL;
} else {
iter->ci_cur = CBMEM_ENTRY_NEXT(iter->ci_cur);
}
}
return (hdr);
}
int
cbmem_flush(struct cbmem *cbmem)
{
int rc;
rc = cbmem_lock_acquire(cbmem);
if (rc != 0) {
goto err;
}
cbmem->c_entry_start = NULL;
cbmem->c_entry_end = NULL;
cbmem->c_buf_cur_end = NULL;
rc = cbmem_lock_release(cbmem);
if (rc != 0) {
goto err;
}
return (0);
err:
return (rc);
}
int
cbmem_read(struct cbmem *cbmem, struct cbmem_entry_hdr *hdr, void *buf,
uint16_t off, uint16_t len)
{
int rc;
rc = cbmem_lock_acquire(cbmem);
if (rc != 0) {
goto err;
}
/* Only read the maximum number of bytes, if we exceed that,
* truncate the read.
*/
if (off + len > hdr->ceh_len) {
len = hdr->ceh_len - off;
}
if (off > hdr->ceh_len) {
rc = -1;
cbmem_lock_release(cbmem);
goto err;
}
memcpy(buf, (uint8_t *) hdr + sizeof(*hdr) + off, len);
rc = cbmem_lock_release(cbmem);
if (rc != 0) {
goto err;
}
return (len);
err:
return (-1);
}
int
cbmem_walk(struct cbmem *cbmem, cbmem_walk_func_t walk_func, void *arg)
{
struct cbmem_entry_hdr *hdr;
struct cbmem_iter iter;
int rc;
rc = cbmem_lock_acquire(cbmem);
if (rc != 0) {
goto err;
}
cbmem_iter_start(cbmem, &iter);
while (1) {
hdr = cbmem_iter_next(cbmem, &iter);
if (hdr == NULL) {
break;
}
rc = walk_func(cbmem, hdr, arg);
if (rc == 1) {
break;
}
}
rc = cbmem_lock_release(cbmem);
if (rc != 0) {
goto err;
}
return (0);
err:
return (rc);
}