Linux内核实现了以下常用的内建数据结构,主要有:
链表
队列
映射
二叉树
今天详细学习一下队列的知识,内核中的队列是以字节形式保存数据的,所以获取数据的时候,需要知道数据的大小。Linux内核通用队列实现称为kfifo。
提供了两个主要操作:enqueue(入队列)和dequeue(出队列)。kfifo对象维护两个偏移量:入口偏移和出口偏移。入口偏移就是下次入队列时的位置,出口偏移就是下一次出队列时的位置。出口偏移总是小于等于入口偏移,否则无意义。
struct kfifo {
unsigned char *buffer; //the buffer holding the data
unsigned int size; //the size of the allocated buffer
unsigned int in; //data is added at offset (in % size)
unsigned int out;//data is extracted from off. (out % size)
spinlock_t *lock; //protects concurrent modifications
};
动态创建和初始化kfifo:
int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask);
该函数创建并且初始化一个大小为size的kfifo,同时为之分配了内存(kmalloc函数)。
值得注意的是,size必须是2的幂,若传入的size不是2的幂,函数就会向上扩展至2的幂。
若先前分配了内存空间buffer,将其初始化为kfifo:
void kfifo_init(struct kfifo *fifo, void *buffer, unsigned int size);
静态声明kfifo:
DECLARE_KFIFO(name, size);
INIT_KFIFO(name);
unsigned int kfifo_in(struct kfifo *fifo, const void *from, unsigned int len)
该函数把from指针所指的len字节的数据拷贝到fifo所指队列中。若成功,返回推入数据的字节大小;如果队列中空闲字节小于len,则拷贝剩余空间的字节数;若返回值为0,说明队列已满。
unsigned int kfifo_out(struct kfifo *fifo, void *to, unsigned int len);
该函数从fifo队列中拷贝长度为len字节的数据到to指向的缓冲区,成功则返回拷贝的数据长度,若队列中数据大小小于len则返回实际读取的数据长度。
若仅仅是想“偷窥”队列中的数据,而不想真的删除它:
unsigned int kfifo_out_peek(struct kfifo *fifo, void *to, unsigned int len, unsigned offset);
其中参数offset指向队列中的索引位置,若该参数为0,则读队列头。
获取kfifo队列的大小:
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_avoil(struct kfifo *fifo);
判断队列是否为空:
static inline int kfifo_is_empty(struct kfifo *fifo);
//若为空返回非0值,否则返回0
判断队列是否满:
static inline unsigned int kfifo_is_full(struct kfifo *fifo);
//若队列已满返回非0值,否则返回0
重置队列就是抛弃队列中的所有数据:
static inline void kfifo_reset(struct kfifo *fifo);
撤销一个使用kfifo_alloc()分配的队列:
void kfifo_free(struct kfifo *fifo);
若是使用kfifo_init()方法创建的队列,就需要手动去释放相关的内存。