linux内核入门之kfifo介绍(1)

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


你可能感兴趣的:(linux内核入门)