Linux Kernel/IIO 软件采样缓冲 / kfifo

用环形 FIFO 暂存传感器采样

Linux IIO 的 kfifo 缓冲在采样进入内核与用户态读取之间暂存数据,按先进先出顺序交付采样记录。

v6.12内存管理核验 2026-10-08
相关概念

工程问题#

采样产生与用户态读取不同步,需要有界缓冲吸收短时速率差,同时避免为每个样本单独分配链表节点。

实际实现#

IIO 按采样记录大小配置 kfifo。底层用数组及 in、out 计数器组织环形存储,容量取二次幂,索引通过掩码回绕;跨越末尾的数据分两段复制。

处理流程#

  1. 按记录大小和缓冲长度分配数组。
  2. 采样路径用 kfifo_in 追加一个记录。
  3. 到数组末端时继续从头部写入。
  4. 读取路径按 FIFO 顺序复制给用户态并推进读位置。

源码片段#

固定版本 · 原文摘录
lib/kfifo.cv6.12 · L93–L112
查看原文件
93	unsigned int size = fifo->mask + 1;94	unsigned int esize = fifo->esize;95	unsigned int l;9697	off &= fifo->mask;98	if (esize != 1) {99		off *= esize;100		size *= esize;101		len *= esize;102	}103	l = min(len, size - off);104105	memcpy(fifo->data + off, src, l);106	memcpy(fifo->data, src + l, len - l);107	/*108	 * make sure that the data in the fifo is up to date before109	 * incrementing the fifo->in index counter110	 */111	smp_wmb();112}
kfifo_copy_in

off 与 mask 相与得到环内位置;先复制到数组末尾,再把剩余数据写到头部。esize 把元素单位换为字节,smp_wmb 保证数据写入先于调用方发布新的 in 计数;这不是任意多生产者的无锁协议。

片段为 kfifo_copy_in 的连续函数体。可写容量由调用者 __kfifo_in 检查,写计数器在复制完成后推进;IIO 的一元素入队不能误读成一字节。

收益与取舍#

工程分析

带来的收益

  • 循环复用预分配存储,避免逐样本节点分配。
  • 有界容量让缓冲内存开销明确。

付出的代价

  • 缓冲满时本次入队失败,IIO 回调返回 EBUSY。
  • 多生产者或多消费者场景仍需相应同步。

可比较的选择

链式队列可以逐节点增长,但需要额外分配、指针存储和容量控制。

版本与适用范围#

对应 IIO 使用 kfifo 的采样缓冲路径;一条记录可包含多个字节。环形表示不自动保证任意多线程组合均无需锁。

参考来源#

源码、官方文档与原始论文
01
Linux v6.12:IIO 入队与用户态读取

drivers/iio/buffer/kfifo_buf.c · iio_store_to_kfifo; iio_read_kfifo; __iio_allocate_kfifo

源码v6.12
02
Linux v6.12:FIFO 环形复制

lib/kfifo.c · kfifo_copy_in; __kfifo_in

源码v6.12

相关实现与比较#

4 个相关案例
nginx·HTTP upstream 配置解析release-1.26.3

nginx 解析 upstream 块时,用 ngx_array_t 连续保存服务器条目;每遇到一条 server 指令便追加一个元素。

附源码片段 · 通信与流量
14 个匹配案例