kfifo环形缓冲区
结论在前:环形缓存区在实际的使用中频率还是很大的,其实写一个rangbuff大家都会.但是随着使用的越来越大,现在不仅仅局限在实现上了,对代码的美观和效率越来越讲究,哪怕可以减少一句话看起来也舒服一点,特别是在写驱动库的时候,好了讲正题了
请看下面这张图( Linux Device Drivers chapter 5, page124):
假设我们的fifo size定义的为16,且我们put了10个节点,get了5个节点,则图应该如下所示:
此时in = 10 & 0B1111 = 10, out = 5 & 0B1111 = 5.
那么在这个基础上, 我们继续put10个节点会发生什么情况?
in = (10 +10)& 0B1111 = 0B0100, 此时 in 在什么位置?
经过mask的”处理”, in 又回到了队列的开头。
可以看到,仅仅一个mask,就就将一个线性的队列转换成了环形队列。实在是不可思议,却又如此简洁,清晰。
本文引用:
https://www.cnblogs.com/syyxy/p/10033511.html
https://shequ.stmicroelectronics.cn/forum.php?mod=viewthread&tid=614991
static inline unsigned int kfifo_put(struct kfifo *fifo,
const unsigned char *buffer, unsigned int len)
{
unsigned long flags;
unsigned int ret;
spin_lock_irqsave(fifo->lock, flags);
ret = __kfifo_put(fifo, buffer, len);
spin_unlock_irqrestore(fifo->lock, flags);
return ret;
}
static inline unsigned int kfifo_get(struct kfifo *fifo,
unsigned char *buffer, unsigned int len)
{
unsigned long flags;
unsigned int ret;
spin_lock_irqsave(fifo->lock, flags);
ret = __kfifo_get(fifo, buffer, len);
//当fifo->in == fifo->out时,buufer为空
if (fifo->in == fifo->out)
fifo->in = fifo->out = 0;
spin_unlock_irqrestore(fifo->lock, flags);
return ret;
}
unsigned int __kfifo_put(struct kfifo *fifo,
const unsigned char *buffer, unsigned int len)
{
unsigned int l;
//buffer中空的长度
len = min(len, fifo->size - fifo->in + fifo->out);
/*
* Ensure that we sample the fifo->out index -before- we
* start putting bytes into the kfifo.
*/
smp_mb();
/* first put the data starting from fifo->in to buffer end */
l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
/* then put the rest (if any) at the beginning of the buffer */
memcpy(fifo->buffer, buffer + l, len - l);
/*
* Ensure that we add the bytes to the kfifo -before-
* we update the fifo->in index.
*/
smp_wmb();
fifo->in += len; //每次累加,到达最大值后溢出,自动转为0
return len;
}
unsigned int __kfifo_get(struct kfifo *fifo,
unsigned char *buffer, unsigned int len)
{
unsigned int l;
//有数据的缓冲区的长度
len = min(len, fifo->in - fifo->out);
/*
* Ensure that we sample the fifo->in index -before- we
* start removing bytes from the kfifo.
*/
smp_rmb();
/* first get the data from fifo->out until the end of the buffer */
l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
/* then get the rest (if any) from the beginning of the buffer */
memcpy(buffer + l, fifo->buffer, len - l);
/*
* Ensure that we remove the bytes from the kfifo -before-
* we update the fifo->out index.
*/
smp_mb();
fifo->out += len; //每次累加,到达最大值后溢出,自动转为0
return len;
}