一、kfifo原理
kfifo实现原理是采用循环(环形)队列。
1 | |
二、kfifo特点
1、采用环形缓冲区来实现,提供一个无边界的字节流服务。采用环形缓冲区的好处为,当一个数据元素被用掉后,其余数据元素不需要移动其存储位置,从而减少拷贝提高效率。
2、保证缓冲区大小为2的次幂,不是的向上取整为2的次幂(很重要)。
3、使用无符号整数保存输入(in)和输出(out)的位置,在输入输出时不对in和out的值进行模运算,而让其自然溢出,并能够保证in-out的结果为缓冲区中已存放的数据长度。
4、将需要取模的运算用 & 操作代替( a % size = (a & (size − 1)) ), 这需要size保证为2的次幂。
5、使用内存屏障(Memory Barrier)技术,实现单消费者和单生产者对kfifo的无锁并发访问(包括多CPU的情况),多个消费者、生产者的并发访问还是需要加锁的。
关于kfifo中内存屏障的使用,请参考https://www.linuxidc.com/Linux/2016-12/137936.htm。
三、kfifo功能函数之创建队列
kfifo提供两种创建队列的方法,动态创建和静态创建。
1、动态创建
(1)、kfifo_alloc
1 | |
该函数创建并初始化一个size大小的kfifo。内核使用gfp_mask标识符分配队列的缓冲区内存。如果成功,函数返回0,错误则返回负数的错误码。注意kfifo_alloc申请的内存是在物理地址上是连续的
(2)、kfifo_init
如果要自己分配缓冲区,可以调用函数:
1 | |
2、静态创建
DECLARE_KFIFO(name, size) ;
INIT_KFIFO(name);
四、入队操作
对于推入队列数据,kfifo提供三大类函数:常规函数, 将用户空间数据推入队列的函数,带记录域功能的函数。
1)常规函数
unsigned int kfifo_in(struct kfifo *fifo, const void *from, unsigned int len);
unsigned int kfifo_in_locked(struct kfifo *fifo, const void *from, unsigned int n, spinlock_t *lock);
2)将用户空间数据推入队列的函数
int kfifo_from_user(struct kfifo *fifo, const void __user *from, unsigned int n, unsigned *lenout);
unsigned int kfifo_from_user_rec(struct kfifo *fifo, const void __user *from, unsigned int n, unsigned int recsize);
3)带记录域功能的函数
unsigned int kfifo_in_rec(struct kfifo *fifo, void *from, unsigned int n, unsigned int recsize);
五、出队
对于摘取队列数据,kfifo提供三大类函数:常规函数, 摘取队列数据至用户空间的函数,带记录域功能的函数。
(1)、常规函数
1 | |
(2)、摘取队列数据至用户空间的函数
1 | |
(3)、带记录域功能的函数
1 | |
六、获取队列长度、判空等操作
(1)、获取队列缓冲区大小
1 | |
(2)、获取队列已推入的数据大小
1 | |
(3)、获取队列可用空间大小
1 | |
(4)、判断队列是否空
1 | |
(5)、判断队列是否满
1 | |
七、重置和撤销队列
(1)、重置队列
1 | |
(2)、撤销队列
如果队列是由函数kfifo_alloc创建,则撤销队列使用:
1 | |
如果队列是由函数kfifo_init创建,则你需要负责释放相关缓冲。