linux的kfifo有以下注意点
1.当向fifo填充数据时称作put,这将会累加in字段,当向fifo取数据时称作get,这将会累加out字段。
2.对于只有一个生产者和一个消费者情形,可以不用对加锁,如有多个则需要加锁
3.当fifo缓冲区的size时2的次方时,kfifo->in % kfifo->size 可以转化为 kfifo->in & (kfifo->size – 1)
,否则不能。
4.in和out字段需要定义成无符号字段,当增加到最大值时,产生溢出从0就开始,以此循环使用
5.对于多个cpu,在每次读写in、out字段之前需要加内存屏障,1个cpu则不需要
下面是单核、一个生产者和一个消费者情形、buff size不是2的次方、1个cpu kfifo的例子
//filename:kfifo.c
#include "kfifo.h"
#define min(a,b) ((a) < (b) ? (a):(b))
int kFifoInit(kfifo_t *fifo, unsigned char *buffer, unsigned int size)
{
if (!fifo)
return -1;
if(!buffer)
return -1;
fifo->buffer = buffer;
fifo->size = size;
fifo->in = fifo->out = 0;
return 0;
}
unsigned int kFifoPut(kfifo_t *fifo, unsigned char *buffer, unsigned int len)
{
unsigned int l;
len = min(len, fifo->size - fifo->in + fifo->out);/*可能是缓冲区的空闲长度或者要写长度*/
/* first put the data starting from fifo->in to buffer end*/
//l = min(len, fifo->size - (fifo->in & (fifo->size -1)));
l = min(len, fifo->size - (fifo->in % (fifo->size)));
//memcpy((fifo->buffer + (fifo->in & (fifo->size -1))), buffer, l);
memcpy((fifo->buffer + (fifo->in % (fifo->size))), buffer, l);
/* then put the rest (if any) at the beginning of the buffer*/
memcpy(fifo->buffer, buffer + l, len - l);
fifo->in += len;
return len;
}
unsigned int kFifoGet(kfifo_t *fifo, unsigned char *buffer, unsigned int len)
{
unsigned int l;
len = min(len, fifo->in - fifo->out); /*可读数据*/
/* first get the data from fifo->out until the end of the buffer*/
//l = min(len, fifo->size - (fifo->out & (fifo->size -1)));
l = min(len, fifo->size - (fifo->out % (fifo->size)));
//memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size -1)), l);
memcpy(buffer, fifo->buffer + (fifo->out % (fifo->size)), l);
/* then get the rest (if any) from the beginning of the buffer*/
memcpy(buffer + l, fifo->buffer, len - l);
fifo->out += len;
return len;
}
unsigned int kFifoPeer(kfifo_t *fifo, unsigned char *buffer, unsigned int len)
{
unsigned int l;
len = min(len, fifo->in - fifo->out); /*可读数据*/
/* first get the data from fifo->out until the end of the buffer*/
//l = min(len, fifo->size - (fifo->out & (fifo->size -1)));
l = min(len, fifo->size - (fifo->out % (fifo->size)));
//memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size -1)), l);
memcpy(buffer, fifo->buffer + (fifo->out % (fifo->size)), l);
/* then get the rest (if any) from the beginning of the buffer*/
memcpy(buffer + l, fifo->buffer, len - l);
return len;
}
void kFifoReset(kfifo_t *fifo)
{
fifo->in = fifo->out = 0;
}
unsigned int kFifoLen(kfifo_t *fifo)
{
return fifo->in - fifo->out;
}
unsigned int kFifoAviable(kfifo_t *fifo)
{
return fifo->size - kFifoLen(fifo);
}
//full 1
unsigned int kFifoFull(kfifo_t *fifo)
{
return fifo->size == kFifoLen(fifo);
}
//empty 1
unsigned int kFifoEmpty(kfifo_t *fifo)
{
return fifo->in == fifo->out;
}
//filename:kfifo.h
#ifndef _KFIFO_H_
#define _KFIFO_H_
#include "soc_types.h"
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
typedef struct kfifo
{
unsigned char *buffer;/* the buffer holding the data*/
unsigned int size;/* the size of the allocated buffer*/
unsigned int in;/* data is added at offset (in % size)*/
unsigned int out;/* data is extracted from off. (out % size)*/
}kfifo_t;
extern int kFifoInit(kfifo_t *fifo, unsigned char *buffer, unsigned int size);
extern unsigned int kFifoPut(kfifo_t *fifo, unsigned char *buffer, unsigned int len);
extern unsigned int kFifoGet(kfifo_t *fifo, unsigned char *buffer, unsigned int len);
extern unsigned int kFifoPeer(kfifo_t *fifo, unsigned char *buffer, unsigned int len);
extern void kFifoReset(kfifo_t *fifo);
extern unsigned int kFifoLen(kfifo_t *fifo);
extern unsigned int kFifoAviable(kfifo_t *fifo);
extern unsigned int kFifoFull(kfifo_t *fifo); //full 1
extern unsigned int kFifoEmpty(kfifo_t *fifo); //empty 1
#endif