在操作系统内核中,一个常见的编程模式就是生产者和消费者。实现这种模式的最容易的方式就是队列。生产者将数据插入队列,消费者将数据移出队列。消费者以数据进队的顺序消费数据。
内核中通用队列的实现称为kfifo,其实现文件位于kernel/kfifo.c中。本部分讨论的API接口是基于2.6.33的。Linux的kfifo工作方式与其他队列一样,提供两个主要的操作:enqueue()和dequeue()。kfifo对象维护了两个偏移量:入口偏移量和出口偏移量。入口偏移量是下次进队发生的位置,出口偏移量是出队发生的位置。出口偏移量问题小于或等于入口偏移量。enqueue操作从入口偏移量处开始,将数据拷贝到队列中,操作完成后,入口偏移量相应的增加(拷进的数据长度)。dequeue操作从出口偏移量处开始,将数据拷贝出队列,操作完成后,出口偏移量相应地增加(拷出的数据长度)。
创建一个队列
int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask);
该函数创建和初始化一个大小为size字节的队列。(同时为之分配内存空间)
例子:
structkfifo fifo; intret; ret= kfifo_alloc(&kifo, PAGE_SIZE, GFP_KERNEL); if(ret) returnret;
|
自建队列函数
/**
* kfifo_init - initialize a fifo using a preallocated buffer(使用已经分配了内存的buffer来初始化一个fifo)
* @fifo: the fifo to assign the buffer
* @buffer: the preallocated buffer to be used
* @size: the size of the internal buffer, this have to be a power of 2
*
* This macro initialize a fifo using a preallocated buffer.
*
* The numer of elements will be rounded-up to a power of 2.
* Return 0 if no error, otherwise an error code.
*/
void kfifo_init(struct kfifo *fifo, void *buffer, unsigned int size); //buffer指向已经分配好的内存区域
静态定义一个队列
DECLARE_KFIFO(name,size);
INIT_KFIFO(name);
其中,队列的大小必须是2的指数。
入队
unsigned int kfifo_in(struct kfifo *fifo, const void *from, unsigned int len); //如果队列满了,不会引起阻塞,只是写入的数据无效
出队
unsigned int kfifo_out(struct kfifo *fifo, void *to, unsigned int len); //如果队列为空,不会引起阻塞,只是读取的数据为空
unsigned int kfifo_out_peek(struct kfifo *fifo, void *to, unsigned int len,
unsigned offset);
获取队列的大小
static inline unsigned int kfifo_size(struct kfifo *fifo);
该函数用于获取用于存储kfifo队列的缓冲区的总大小。
static inline unsigned int kfifo_len(struct kfifo *fifo);
该函数用于获取进入kfifo队列的字节数。
static inline unsigned int kfifo_avail(struct kfifo *fifo);
队列中可用于写入的剩余缓冲区的大小。
static inline int kfifo_is_empty(struct kfifo *fifo);
static inline int kfifo_is_full(struct kfifo *fifo);
上述两个函数分别用于判断队列是否为空或满。
重置和销毁队列
static inline void kfifo_reset(struct kfifo *fifo);
重置一个队列
void kfifo_free(struct kfifo *fifo);
释放一个kfifo,与kfifo_alloc()对应。
如果创建kfifo的时候使用的是kfifo_init()函数,那么提供相应的函数来释放缓冲区,而不是用kfifo_free()。