1.介绍
kfifo是Linux内核一个通用的队列实现,它提供了两个主要操作:入队(in)和出队(out).kfifo对象维护了两个offset:in offset和out offset.in offset指示了下次入队的位置,而out offset指示了下次出队的位置.
入队(in)操作将数据从队列的in offset位置复制到队列中,完成后,in offset的值会加上数据的长度.出队(out)操作将数据从队列的out offset位置复制出来,完成后将out offset的值减去数据的长度.当out offset等于in offset,表明队列为空.当in offset等于队列的长度,表明队列已满.
kfifo的定义和实现分别在和文件中.
2.kfifo操作
a.创建队列
动态创建:
int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask);
该函数创建和初始化一个size字节的kfifo队列.成功,返回0;出错则返回负error code.
使用自己定义的buffer,使用kfifo_init函数:
void kfifo_init(struct kfifo *fito, void *buffer, unsigned int size);
该函数创建和初始化一个以buffer为内存空间的队列.
使用kfifo_alloc和kfifo_init时,size必须是2的幂.
静态声明:
DECLARE_KFIFO(name, size);
INIT_KFIFO(name);
这两个宏创建一个名称为name,大小为size字节的队列.同上,size必须是2的幂.
b.入队
usinged int kfifo_in(struct kfifo *fifo, const void *from, unsigned int len);
该函数从from中复制len个字节的数据到fifo队列.成功则返回入队的字节数.如果fifo的可用空间小于len,则只复制可用空间的字节长度.因此返回值可能小于len或为0(没有复制任何数据).
c.出队
unsigned int kfifo_out(struct kfifo *fifo, void *to, unsigned int len);
该函数从队列中复制最多len个字节的数据到to.成功则返回已复制数据的长度.如果队列的数据少于len,则返回值可能len.
数据出队后将不能再次访问.
unsigned int kfifo_out_peek(struct kfifo *fifo, void *to, unsigned int len, unsigned offset);
该函数从列表的offset位置开始获取len字节的数据,但队列的数据仍然可以再次访问,out offset没有被更改.
d.获取队列大小
static inline unsigned int kfifo_size(struct kfifo *fifo);
该函数返回队列的空间总大小.
static inline unsigned int kfifo_len(struct kfifo *fifo);
该函数返回队列中已入队字节数.
static inline unsigned int kfifo_avail(struct kfifo *fifo);
该函数返回队列的可用空间的大小.
static inline int kfifo_is_empty(struct kfifo *fifo);
该函数测试kfifo是否为空.
static inline int kfifo_is_full(struct kfifo *fifo);
该函数测试kfifo是否已满.
e.重置和销毁队列
static inline void kfifo_reset(struct kfifo *fifo);
该函数重置队列.
void kfifo_free(struct kfifo *fifo);
该函数销毁用kfifo_alloc()创建的队列.
3.示例
a.目录结构
|--kfifo_test.c
|--Makefile
b.源代码
文件kfifo_test.c:
#include
#include
#include
#include
void prt_kfifo_size(struct kfifo *fifo)
{
printk(KERN_INFO "kfifo size : %u bytes\n", kfifo_size(fifo));
printk(KERN_INFO "kfifo len : %u bytes\n", kfifo_len(fifo));
printk(KERN_INFO "kfifo avail : %u bytes\n", kfifo_avail(fifo));
}
static int test_init(void)
{
struct kfifo fifo;
int ret;
int i;
int buf[1024];
int nbytes;
ret = kfifo_alloc(&fifo, 1024, GFP_KERNEL);
if (ret)/*some error happened*/
return ret;
for (i = 0; i < 32; i++) {
kfifo_in(&fifo, &i, sizeof(i));
}
prt_kfifo_size(&fifo);
nbytes = kfifo_out_peek(&fifo, buf, 1024, 0);
printk(KERN_INFO "peek : %d bytes\n", nbytes);
for (i = 0; i < nbytes/sizeof(int); i++) {
printk(KERN_INFO "%d ", buf[i]);
}
printk(KERN_INFO "\n======= after peek =======\n");
prt_kfifo_size(&fifo);
nbytes = kfifo_out(&fifo, buf, sizeof(int));
printk(KERN_INFO "out : %d bytes\n", nbytes);
printk(KERN_INFO "\n======= after out =======\n");
prt_kfifo_size(&fifo);
kfifo_free(&fifo);/*must do this*/
return 0;
}
static void test_exit(void)
{
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ice");
/*
kfifo size : 1024 bytes
kfifo len : 128 bytes
kfifo avail : 896 bytes
peek : 128 bytes
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
======= after peek =======
kfifo size : 1024 bytes
kfifo len : 128 bytes
kfifo avail : 896 bytes
out : 4 bytes
======= after out =======
kfifo size : 1024 bytes
kfifo len : 124 bytes
kfifo avail : 900 bytes
*/
文件Makefile:
obj-m := kfifo_test.o
KERNELDIR ?= /lib/modules/`uname -r`/build
PWD := `pwd`
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules