队列
队列也是一种链表,只是针对队列的操作只能是从队尾插入,从队首删除。在操作系统中有很多这种数据结构的用武之地,一般是一个进程产生数据,另外一个进程处理数据,如Linux中网络数据包的处理,进程之间使用管道通信等,都是这种情况。Linux内核中队列称作kfifo,其对应的源文件时kernel/kfifo.c,<linux/kfifo.h>中包含了其声明。
kfifo提供了两种操作,入队(in)和出队(out),为了记录下一次出队或者入队的位置,kfifo维护了两个变量in和out。入队操作会将数据拷贝至队列中,具体位置由in确定,然后根据数据大小更新in,标识下一入队发生的位置。出队的操作与之类似。当in和out相等时,队列为空,此时不能执行出队操作。当in等于队列长度时,不能执行入队操作。
和其他内核对象一样,定义并初始化队列也有静态和动态两种方式。
动态方法
这个函数创建并初始化一个大小为size的队列。gfp_mask指定内存分配方式,可以取值GFP_KERNEL,GFP_ATOMIC,当在进程上下文分配内存,使用GFP_KERNEL,此时,允许kmalloc函数因为等待内存页释放而睡眠。如果,在中断上下文中分配内存,使用GFP_ATOMIC,此时kmalloc不能睡眠,此时可能由于内存不足导致分配失败。
如果,你想自己分配队列空间,可以使用下面这个函数。
这个函数创建并初始化kfifo,这个kfifo使用buffer指向的大小为size的区域作为队列节点存储区域。注意,size必须为2的n次方,即size = 2n。
静态方法
DECLARE_KFIFO(name, size);
INIT_KFIFO(name);
入队
但kfifo成功创建后,就可以想队列尾部放入数据
这个函数将buf开始的n个字符插入队列。这里是尽最大努力的拷贝,也就是说如果空间不足,拷贝的大小就是可用空间可容纳的大小。
出队
这个函数从队列中读出长度为n的数据,然后放入以buf表示的缓冲区中。出队意味着以后数据已不在队列中,你也可以调用函数kfifo_out_peek来读取数据而不从队列中删除这些数据。对于队列的操作需要注意的就是同步的问题,因为这等效于读者和写者问题。有兴趣可以看看内核中的实现。
其他队列的操作还有很多,代码文件位于linux/kfifo.c以及include/linux/kfifo.h中。