本文分析的原代码版本: 2.6.24.4
kfifo的定义文件: kernel/kfifo.c
kfifo的头文件: include/linux/kfifo.h
kfifo是内核里面的一个First In First Out数据结构,它采用环形循环队列的数据结构来实现,提供一个无边界的字节流服务,并且使用并行无锁编程技术,即当它用于只有一个入队线程和一个出队线程的场情时,两个线程可以并发操作,而不需要任何加锁行为,就可以保证kfifo的线程安全。
下文着重于代码剖析,各部分代码后面有关键点说明,同时可参考注释进行理解:
struct kfifo {
unsigned char *buffer; /* the buffer holding the data : 用于存放数据的缓存 */
unsigned int size; /* the size of the allocated buffer : 空间的大小,在初化时将它向上扩展成2的幂,为了高效的进行与操作取余,后面会详解 */
unsigned int in; /* data is added at offset (in % size) : 如果使用不能保证任何时间最多只有一个读线程和写线程,需要使用该lock实施同步*/
unsigned int out; /* data is extracted from off. (out % size) :一起构成一个循环队列。 in指向buffer中队头,而且out指向buffer中的队尾 */
spinlock_t *lock; /* protects concurrent modifications : 用于put和get过程中加锁防止并发*/
};
以上是kfifo的数据结构,kfifo主要提供了如下操作:
//根据给定buffer创建一个kfifo
struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
gfp_t gfp_mask, spinlock_t *lock);
//给定size分配buffer和kfifo
struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask,
spinlock_t *lock);
//释放kfifo空间
void kfifo_free(struct kfifo *fifo);
//向kfifo中添加数据
unsigned int kfifo_put(struct kfifo *fifo,
const unsigned char *buffer, unsigned int len);
//从kfifo中取数据
unsigned int kfifo_get(struct kfifo *fifo,
unsigned char *buffer, unsigned int len);
//获取kfifo中有数据的buffer大小
unsigned int kfifo_len(struct kfifo *fifo);
(1)初始化部分:
/* 创建队列 */ struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
gfp_t gfp_mask, spinlock_t *lock)
{
struct kfifo *fifo;
/* size must be a power of 2 :判断是否为2的幂*/
BUG_ON(!is_power_of_2(size));
fifo = kmalloc(sizeof(struct kfifo), gfp_mask);
if (!fifo)
return ERR_PTR(-ENOMEM);
fifo->buffer = buffer;
fifo->size = size;
fifo->in = fifo->out = 0;
fifo->lock = lock;
return fifo;
}
/* 分配空间 */ struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock)
{
unsigned char *buffer;
struct kfifo *ret;
if (!is_power_of_2(size)) { /* 判断是否为2的幂 */
BUG_ON(size > 0x80000000);
size = roundup_pow_of_two(size); /* 如果不是则向上扩展成