菜鸟笔记
提升您的技术认知

Linux环形工作队列KFIFO的使用说明

这里是基于Android7.1 kernel4.4的内核代码下:

Kfifo是内核里面的一个first in first out数据结构,它采用环形循环队列(ringbuffer)的数据结构来实现;它提供一个无边界的字节流服务,最重要的一点是,它使用并行无锁编程技术,即当它用于只有一个入队线程和一个出队线程的场景时,两个线程可以并发操作,而不需要任何加锁行为,就可以保证kfifo的线程安全

下面这里是我在跟amlogic android7.1 IR驱动代码时候看到的fifo的简单调用,这里只是拿来举例:

#include <linux/kfifo.h> //添加头文件

struct remote_raw_handle {
  
	struct list_head list;
	struct remote_dev *dev;
	struct task_struct *thread;
	struct kfifo_rec_ptr_1 kfifo;/* fifo for the pulse/space durations */ ,定义kfifo_rec类型
	spinlock_t lock;

	enum raw_event_type last_type;
	unsigned long jiffies_old;
	unsigned long repeat_time;
	unsigned long max_frame_time;
};


ret = kfifo_alloc(&dev->raw->kfifo, sizeof(struct remote_raw_event)*MAX_REMOTE_EVENT_SIZE, GFP_KERNEL); //分配kfifo内存和初始化
retval = kfifo_len(&raw->kfifo); //返回FIFO中可用的字节数
if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev)) //把数据存入FIFO中,也就是入队列sizeof(*ev)个字节到fifo中。返回成功copy的个数
retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev)); //从FIFO获取一些数据, 也就是出队列sizeof(ev)个字节到ev中。返回成功copy的个数。
kfifo_free(&dev->raw->kfifo); //释放fifo占用

一些常用接口介绍:

首先定义一个fifo结构体:这里可以这样定义:struct kfifo fifo
/*
 * define compatibility "struct kfifo" for dynamic allocated fifos
 */
struct kfifo __STRUCT_KFIFO_PTR(unsigned char, 0, void);


 /*
 * define kfifo_rec types
 */
struct kfifo_rec_ptr_1 __STRUCT_KFIFO_PTR(unsigned char, 1, void);
struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void);


 /**
  * kfifo_len - returns the number of used elements in the fifo
  * @fifo: address of the fifo to be used
  */
kfifo_len(fifo) //返回fifo中使用的元素数量


/**
 * kfifo_avail - returns the number of unused elements in the fifo
 * @fifo: address of the fifo to be used
 */
kfifo_avail(fifo) //返回fifo中未使用元素的数量

/**
 * kfifo_in - put data into the fifo
 * @fifo: address of the fifo to be used
 * @buf: the data to be added
 * @n: number of elements to be added
 *
 * This macro copies the given buffer into the fifo and returns the
 * number of copied elements.
 *
 * Note that with only one concurrent reader and one concurrent
 * writer, you don't need extra locking to use these macro.
 */
kfifo_in(fifo, buf, n) //将buf的n个数据放入fifo,返回复制元素的数量n


/**
 * kfifo_out - get data from the fifo
 * @fifo: address of the fifo to be used
 * @buf: pointer to the storage buffer
 * @n: max. number of elements to get
 *
 * This macro get some data from the fifo and return the numbers of elements
 * copied.
 *
 * Note that with only one concurrent reader and one concurrent
 * writer, you don't need extra locking to use these macro.
 */
kfifo_out(fifo, buf, n) //从fifo中得到n个buf的数据,返回复制元素的数量n


/**
 * kfifo_to_user - copies data from the fifo into user space
 * @fifo: address of the fifo to be used
 * @to: where the data must be copied
 * @len: the size of the destination buffer
 * @copied: pointer to output variable to store the number of copied bytes
 *
 * This macro copies at most @len bytes from the fifo into the
 * @to buffer and returns -EFAULT/0.
 *
 * Note that with only one concurrent reader and one concurrent
 * writer, you don't need extra locking to use these macro.
 */
kfifo_to_user(fifo, to, len, copied) //将数据从fifo复制到用户空间


/**
 * kfifo_from_user - puts some data from user space into the fifo
 * @fifo: address of the fifo to be used
 * @from: pointer to the data to be added
 * @len: the length of the data to be added
 * @copied: pointer to output variable to store the number of copied bytes
 *
 * This macro copies at most @len bytes from the @from into the
 * fifo, depending of the available space and returns -EFAULT/0.
 *
 * Note that with only one concurrent reader and one concurrent
 * writer, you don't need extra locking to use these macro.
 */
kfifo_from_user(fifo, from, len, copied) //将一些来自用户空间的数据放入fifo

FIFO环形工作队列使用说明举例:

int ret=0;
int data_count = 0;
Unsigned char tempbuf[1024] = {
  0};
struct kfifo fifo; 


ret = kfifo_alloc(&fifo, 1024, GFP_KERNEL);//分配1024个大小的空间,并初始化。
if(ret)	//返回值为非0,代表出错。
return error;


data_count = kfifo_len(&fifo);//查看fifo空间里的元素个数。
data_count = kfifo_avail(fifo);//查看fifo空间里空闲的个数。


data_count = kfifo_in(&fifo,(void *)(tempbuf),10);//入队列10个字节到fifo中。返回成功copy的个数。
data_count = kfifo_out(&fifo,(void *)(tempbuf),10);//出队列10个字节到tempbuf中。返回成功copy的个数。


ret = kfifo_to_user(&fifo, (void *)_usr,10,&copied);//出队列10个字节到用户空间,copied为copy成功的字节数。
ret = kfifo_from_user(&fifo, (void *) _usr, 10, &copied);// 从用户空间copy 10个字节到队列中,copied为copy成功的字节数。