数据结构:内核kfifo的实践
实践了内核的数据结构kfifo记录下,其特点分析看了下这篇博客写的很详细。https://blog.csdn.net/zhoutaopower/article/details/86491852
fifo.c 实现kfifo的主干函数接口,但是很多有用的接口没有扩展,需要的时候再扩展。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include"fifo.h"
#define min(a, b) \
({ \
typeof(a) _a = (a); \
typeof(b) _b = (b); \
_a <= _b ? _a : _b \
})
static inline int fls(int x)
{
int position;
int i;
if(0 != x)
{
for(i = (x >> 1), position = 0; i != 0; ++position)
i >>= 1;
}
else
{
position = -1;
}
return position+1;
}
static inline unsigned int roundup_pow_of_two(unsigned int x)
{
return 1UL << fls(x - 1);
}
int __kfifo_alloc(struct __kfifo *fifo, unsigned int size, size_t esize)
{
/*
* round up to the next power of 2, since our 'let the indices
* wrap' technique works only in this case.
*/
size = roundup_pow_of_two(size);
fifo->in = 0;
fifo->out = 0;
fifo->esize = esize;
if (size < 2) {
fifo->data = NULL;
fifo->mask = 0;
return -1;
}
// fifo->data = kmalloc_array(esize, size, gfp_mask);
fifo->data = malloc(esize*size);
if (!fifo->data) {
fifo->mask = 0;
return -1;
}
fifo->mask = size - 1;
return 0;
}
int __kfifo_init(struct __kfifo *fifo, void *buffer, unsigned int size, size_t esize)
{
size /= esize;
size = roundup_pow_of_two(size);
fifo->in = 0;
fifo->out = 0;
fifo->esize = esize;
fifo->data = buffer;
if (size < 2) {
fifo->mask = 0;
return -1;
}
fifo->mask = size - 1;
return 0;
}
void __kfifo_free(struct __kfifo *fifo)
{
free(fifo->data);
fifo->in = 0;
fifo->out = 0;
fifo->esize = 0;
fifo->data = NULL;
fifo->mask = 0;
}
/*
* internal helper to calculate the unused elements in a fifo
*/
static inline unsigned int kfifo_unused(struct __kfifo *fifo)
{
return (fifo->mask + 1) - (fifo->in - fifo->out);
}
static void kfifo_copy_in(struct __kfifo *fifo, const void *src, unsigned int len, unsigned int off)
{
unsigned int size = fifo->mask + 1;
unsigned int esize = fifo->esize;
unsigned int l;
off &= fifo->mask;
if (esize != 1) {
off *= esize;
size *= esize;
len *= esize;
}
l = min(len, size - off);
memcpy(fifo->data + off, src, l);
memcpy(fifo->data, src + l, len - l);
/*
* make sure that the data in the fifo is up to date before
* incrementing the fifo->in index counter
*/
// smp_wmb();
}
unsigned int __kfifo_in(struct __kfifo *fifo, const void *buf, unsigned int len)
{
unsigned int l;
l = kfifo_unused(fifo);
if (len > l)
len = l;
kfifo_copy_in(fifo, buf, len, fifo->in);
fifo->in += len;
return len;
}
static void kfifo_copy_out(struct __kfifo *fifo, void *dst,
unsigned int len, unsigned int off)
{
unsigned int size = fifo->mask + 1;
unsigned int esize = fifo->esize;
unsigned int l;
off &= fifo->mask;
if (esize != 1) {
off *= esize;
size *= esize;
len *= esize;
}
l = min(len, size - off);
memcpy(dst, fifo->data + off, l);
memcpy(dst + l, fifo->data, len - l);
/*
* make sure that the data is copied before
* incrementing the fifo->out index counter
*/
// smp_wmb();
}
unsigned int __kfifo_out_peek(struct __kfifo *fifo,
void *buf, unsigned int len)
{
unsigned int l;
l = fifo->in - fifo->out;
if (len > l)
len = l;
kfifo_copy_out(fifo, buf, len, fifo->out);
return len;
}
unsigned int __kfifo_out(struct __kfifo *fifo,
void *buf, unsigned int len)
{
len = __kfifo_out_peek(fifo, buf, len);
fifo->out += len;
return len;
}
fifo.h
#include<stdio.h>
#include<stdlib.h>
struct __kfifo {
unsigned int in; // 入列的时候增加的位置
unsigned int out; // 出列的时候增加的位置
unsigned int mask; // 巧妙的 mask 设计,同时包含了数据的个数信息
unsigned int esize; // 元素的大小
void *data; // 数据
};
int __kfifo_alloc(struct __kfifo *fifo, unsigned int size, size_t esize);
int __kfifo_init(struct __kfifo *fifo, void *buffer,unsigned int size, size_t esize);
void __kfifo_free(struct __kfifo *fifo);
unsigned int __kfifo_in(struct __kfifo *fifo, const void *buf, unsigned int len);
unsigned int __kfifo_out(struct __kfifo *fifo, void *buf, unsigned int len);
test.c
2024-04-07 记录
#include<stdio.h>
#include<stdlib.h>
#include"fifo.h"
typedef struct node
{
int a;
int b;
}node;
int main()
{
int esize = sizeof(node);
int size = 8;
void *buf = NULL;
struct __kfifo fifo;
int count;
node aa;
aa.a = 12;
aa.b = 13;
node bb;
bb.a = 0;
bb.b = 0;
__kfifo_init(&fifo, buf, size, esize);
__kfifo_alloc(&fifo, size, esize);
count = __kfifo_in(&fifo, (void *)&aa, 1); //注意这里传参是node的数量,不是node的大小。一开始实践赋值了node的大小,会有内存溢出。
printf("in count: %d.\n", count);
count = __kfifo_out(&fifo, (void *)&bb, 1);
printf("out count: %d.\n", count);
printf("bb.a :%d, bb.b :%d.\n", bb.a, bb.b);
return 0;
}