feat(kfifo): Add the kernel fifo.
This commit is contained in:
195
include/kernel/mr_kfifo.h
Normal file
195
include/kernel/mr_kfifo.h
Normal file
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* @copyright (c) 2024, MacRsh
|
||||
*
|
||||
* @license SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* @date 2024-09-06 MacRsh First version
|
||||
*/
|
||||
|
||||
#ifndef __MR_KFIFO_H__
|
||||
#define __MR_KFIFO_H__
|
||||
|
||||
#include <kernel/mr_kservice.h>
|
||||
#include <libc/mr_compiler.h>
|
||||
#include <libc/mr_types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* @addtogroup Kfifo
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Kfifo type */
|
||||
typedef struct mr_kfifo {
|
||||
mr_uint8_t *buf;
|
||||
mr_uint32_t mask;
|
||||
mr_uint32_t elem_size;
|
||||
volatile mr_uint32_t in;
|
||||
volatile mr_uint32_t out;
|
||||
} mr_kfifo_t;
|
||||
|
||||
/**
|
||||
* @brief This function initializes a kfifo.
|
||||
*
|
||||
* @param kfifo The kfifo.
|
||||
* @param buf The buffer.
|
||||
* @param size The buffer size(bytes).
|
||||
* @param elem_size The element size(bytes).
|
||||
* @return The element capacity(number).
|
||||
*
|
||||
* @note The buffer will be aligned down to a power of 2.
|
||||
*/
|
||||
mr_uint32_t mr_kfifo_init(mr_kfifo_t *kfifo, void *buf, mr_uint32_t size,
|
||||
mr_uint32_t elem_size);
|
||||
|
||||
/**
|
||||
* @brief This function allocates a kfifo.
|
||||
*
|
||||
* @param kfifo The kfifo.
|
||||
* @param size The buffer size(bytes).
|
||||
* @param elem_size The element size(bytes).
|
||||
* @return The element capacity(number).
|
||||
*
|
||||
* @note The buffer will be aligned up to a power of 2.
|
||||
*/
|
||||
mr_uint32_t mr_kfifo_alloc(mr_kfifo_t *kfifo, mr_uint32_t size,
|
||||
mr_uint32_t elem_size);
|
||||
|
||||
/**
|
||||
* @brief This function frees a kfifo.
|
||||
*
|
||||
* @param kfifo The kfifo.
|
||||
*/
|
||||
void mr_kfifo_free(mr_kfifo_t *kfifo);
|
||||
|
||||
/**
|
||||
* @brief This function pushes data to a kfifo.
|
||||
*
|
||||
* @param kfifo The kfifo.
|
||||
* @param data The data.
|
||||
* @return The actual pushed element number.
|
||||
*/
|
||||
mr_uint32_t mr_kfifo_push(mr_kfifo_t *kfifo, const void *data);
|
||||
|
||||
/**
|
||||
* @brief This function pops data from a kfifo.
|
||||
*
|
||||
* @param kfifo The kfifo.
|
||||
* @param data The data.
|
||||
* @return The actual popped element number.
|
||||
*/
|
||||
mr_uint32_t mr_kfifo_pop(mr_kfifo_t *kfifo, void *data);
|
||||
|
||||
/**
|
||||
* @brief This function puts data to a kfifo.
|
||||
*
|
||||
* @param kfifo The kfifo.
|
||||
* @param buf The buffer.
|
||||
* @param num The buffer number.
|
||||
* @return The actual pushed element number.
|
||||
*/
|
||||
mr_uint32_t mr_kfifo_in(mr_kfifo_t *kfifo, const void *buf, mr_uint32_t num);
|
||||
|
||||
/**
|
||||
* @brief This function peeks data from a kfifo.
|
||||
*
|
||||
* @param kfifo The kfifo.
|
||||
* @param buf The buffer.
|
||||
* @param num The buffer number.
|
||||
* @return The actual peeked element number.
|
||||
*/
|
||||
mr_uint32_t mr_kfifo_peek(mr_kfifo_t *kfifo, void *buf, mr_uint32_t num);
|
||||
|
||||
/**
|
||||
* @brief This function gets data from a kfifo.
|
||||
*
|
||||
* @param kfifo The kfifo.
|
||||
* @param buf The buffer.
|
||||
* @param num The buffer number.
|
||||
* @return The actual popped element number.
|
||||
*/
|
||||
MR_INLINE mr_uint32_t mr_kfifo_out(mr_kfifo_t *kfifo, void *buf,
|
||||
mr_uint32_t num) {
|
||||
/* Pop buffer */
|
||||
num = mr_kfifo_peek(kfifo, buf, num);
|
||||
kfifo->out += num;
|
||||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function gets the element number in a kfifo.
|
||||
*
|
||||
* @param kfifo The kfifo.
|
||||
* @return The element number.
|
||||
*/
|
||||
MR_INLINE mr_uint32_t mr_kfifo_len(mr_kfifo_t *kfifo) {
|
||||
/* Get kfifo element number */
|
||||
return kfifo->in - kfifo->out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function skips elements in a kfifo.
|
||||
*
|
||||
* @param kfifo The kfifo.
|
||||
* @param num The element number.
|
||||
* @return The actual skipped element number.
|
||||
*/
|
||||
MR_INLINE mr_uint32_t mr_kfifo_skip(mr_kfifo_t *kfifo, mr_uint32_t num) {
|
||||
/* Skip buffer */
|
||||
kfifo->out += MR_MIN(num, mr_kfifo_len(kfifo));
|
||||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function gets the available space in a kfifo.
|
||||
*
|
||||
* @param kfifo The kfifo.
|
||||
* @return The available element number.
|
||||
*/
|
||||
MR_INLINE mr_uint32_t mr_kfifo_avail(mr_kfifo_t *kfifo) {
|
||||
/* Get kfifo available space */
|
||||
return (kfifo->mask + 1) - mr_kfifo_len(kfifo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function resets a kfifo.
|
||||
*
|
||||
* @param kfifo The kfifo.
|
||||
*/
|
||||
MR_INLINE void mr_kfifo_reset(mr_kfifo_t *kfifo) {
|
||||
/* Reset kfifo */
|
||||
kfifo->in = kfifo->out = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function checks if a kfifo is empty.
|
||||
*
|
||||
* @param kfifo The kfifo.
|
||||
* @return MR_TRUE on empty, MR_FALSE otherwise.
|
||||
*/
|
||||
MR_INLINE mr_bool_t mr_kfifo_is_empty(mr_kfifo_t *kfifo) {
|
||||
/* Check if kfifo is empty */
|
||||
return kfifo->in == kfifo->out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function checks if a kfifo is full.
|
||||
*
|
||||
* @param kfifo The kfifo.
|
||||
* @return MR_TRUE on full, MR_FALSE otherwise.
|
||||
*/
|
||||
MR_INLINE mr_bool_t mr_kfifo_is_full(mr_kfifo_t *kfifo) {
|
||||
/* Check if kfifo is full */
|
||||
return mr_kfifo_len(kfifo) == (kfifo->mask + 1);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __MR_KFIFO_H__ */
|
||||
172
kernel/kfifo.c
Normal file
172
kernel/kfifo.c
Normal file
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* @copyright (c) 2024, MacRsh
|
||||
*
|
||||
* @license SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* @date 2024-09-06 MacRsh First version
|
||||
*/
|
||||
|
||||
#include <kernel/mr_kfifo.h>
|
||||
#include <libc/mr_string.h>
|
||||
#include <libc/mr_malloc.h>
|
||||
|
||||
/* Kfifo align macro function */
|
||||
#define KFIFO_ALIGN_POW2_UP(_size) \
|
||||
(((_size) & ((_size) - 1)) ? (1U << mr_fls32(_size)) : (_size))
|
||||
#define KFIFO_ALIGN_POW2_DOWN(_size) \
|
||||
(1U << (mr_fls32(_size) - 1))
|
||||
|
||||
mr_uint32_t mr_kfifo_init(mr_kfifo_t *kfifo, void *buf, mr_uint32_t size,
|
||||
mr_uint32_t elem_size) {
|
||||
/* Check arguments */
|
||||
if ((!buf) || (size < 2) || (elem_size == 0) || (elem_size > size)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Align size(down to power of 2) */
|
||||
size = KFIFO_ALIGN_POW2_DOWN(size / elem_size);
|
||||
|
||||
/* Init kfifo */
|
||||
kfifo->buf = buf;
|
||||
kfifo->mask = size - 1;
|
||||
kfifo->in = kfifo->out = 0;
|
||||
kfifo->elem_size = elem_size;
|
||||
return size;
|
||||
}
|
||||
|
||||
mr_uint32_t mr_kfifo_alloc(mr_kfifo_t *kfifo, mr_uint32_t size,
|
||||
mr_uint32_t elem_size) {
|
||||
void *buf;
|
||||
|
||||
/* Check arguments */
|
||||
if ((size == 0) || (elem_size == 0) || (elem_size > size)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Align size(up to power of 2) */
|
||||
size = KFIFO_ALIGN_POW2_UP(size);
|
||||
|
||||
/* Allocate buffer */
|
||||
if (kfifo->buf) {
|
||||
buf = mr_realloc(kfifo->buf, size);
|
||||
} else {
|
||||
buf = mr_malloc(size);
|
||||
}
|
||||
if (!buf) {
|
||||
/* Not enough memory */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Init kfifo */
|
||||
return mr_kfifo_init(kfifo, buf, size, elem_size);
|
||||
}
|
||||
|
||||
void mr_kfifo_free(mr_kfifo_t *kfifo) {
|
||||
/* Check need to free */
|
||||
if (!kfifo->buf) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Free buffer */
|
||||
mr_free(kfifo->buf);
|
||||
kfifo->buf = MR_NULL;
|
||||
}
|
||||
|
||||
mr_uint32_t mr_kfifo_push(mr_kfifo_t *kfifo, const void *data) {
|
||||
mr_uint32_t in;
|
||||
|
||||
/* Check if kfifo is full */
|
||||
if (mr_kfifo_is_full(kfifo)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get in index */
|
||||
in = kfifo->in & kfifo->mask;
|
||||
if (kfifo->elem_size != 1) {
|
||||
in *= kfifo->elem_size;
|
||||
}
|
||||
|
||||
/* Push data */
|
||||
mr_memcpy((mr_uint8_t *)kfifo->buf + in, data, kfifo->elem_size);
|
||||
kfifo->in += 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
mr_uint32_t mr_kfifo_pop(mr_kfifo_t *kfifo, void *data) {
|
||||
mr_uint32_t out;
|
||||
|
||||
/* Check if kfifo is empty */
|
||||
if (mr_kfifo_is_empty(kfifo)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get out index */
|
||||
out = kfifo->out & kfifo->mask;
|
||||
if (kfifo->elem_size != 1) {
|
||||
out *= kfifo->elem_size;
|
||||
}
|
||||
|
||||
/* Pop data */
|
||||
mr_memcpy(data, (mr_uint8_t *)kfifo->buf + out, kfifo->elem_size);
|
||||
kfifo->out += 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
mr_uint32_t mr_kfifo_in(mr_kfifo_t *kfifo, const void *buf, mr_uint32_t num) {
|
||||
mr_uint32_t avail, num2, in, size, n;
|
||||
|
||||
/* Limit length */
|
||||
avail = mr_kfifo_avail(kfifo);
|
||||
if (num > avail) {
|
||||
num = avail;
|
||||
}
|
||||
if (num == 0) {
|
||||
return 0;
|
||||
}
|
||||
num2 = num;
|
||||
|
||||
/* Get in index */
|
||||
in = kfifo->in & kfifo->mask;
|
||||
size = kfifo->mask + 1;
|
||||
if (kfifo->elem_size != 1) {
|
||||
in *= kfifo->elem_size;
|
||||
size *= kfifo->elem_size;
|
||||
num *= kfifo->elem_size;
|
||||
}
|
||||
n = MR_MIN(num, size - in);
|
||||
|
||||
/* Push buffer */
|
||||
mr_memcpy((mr_uint8_t *)kfifo->buf + in, buf, n);
|
||||
mr_memcpy(kfifo->buf, ((mr_uint8_t *)buf) + n, num - n);
|
||||
kfifo->in += num2;
|
||||
return num2;
|
||||
}
|
||||
|
||||
mr_uint32_t mr_kfifo_peek(mr_kfifo_t *kfifo, void *buf, mr_uint32_t num) {
|
||||
mr_uint32_t avail, num2, out, size, n;
|
||||
|
||||
/* Limit size */
|
||||
avail = mr_kfifo_len(kfifo);
|
||||
if (num > avail) {
|
||||
num = avail;
|
||||
}
|
||||
if (num == 0) {
|
||||
return 0;
|
||||
}
|
||||
num2 = num;
|
||||
|
||||
/* Get out index */
|
||||
out = kfifo->out & kfifo->mask;
|
||||
size = kfifo->mask + 1;
|
||||
if (kfifo->elem_size != 1) {
|
||||
out *= kfifo->elem_size;
|
||||
size *= kfifo->elem_size;
|
||||
num *= kfifo->elem_size;
|
||||
}
|
||||
|
||||
/* Pop buffer */
|
||||
n = MR_MIN(num, size - out);
|
||||
mr_memcpy(buf, (mr_uint8_t *)kfifo->buf + out, n);
|
||||
mr_memcpy((mr_uint8_t *)buf + n, kfifo->buf, num - n);
|
||||
return num2;
|
||||
}
|
||||
Reference in New Issue
Block a user