kfifo 的一些伪代码
kfifo_len()
out = LOAD fifo->out
smp_rmb()
len = LOAD fifo->in - out
kfifo_in() kfifo_out()
kfifo_len() kfifo_len()
smp_mb() smp_rmb()
off = LOAD fifo->in + off off = LOAD fifo->out + off
/* memcpy */ /* memcpy */
smp_wmb() smp_mb()
STORE fifo->in += off STORE fifo->out += off
kfifo_in 只修改 fifo->in 的值,含一个 STORE 指令,及若干 fifo->out fifo->in 的 LOAD 指令
kfifo_out 相反,只修改 kfifo->out 的值,同样含一个 STORE 指令及若干 LOAD 指令
把代码中的内存屏障去掉
kfifo_len()
out = LOAD fifo->out
/* smp_rmb() */
len = LOAD fifo->in - out
kfifo_in() kfifo_out()
kfifo_len() kfifo_len()
/* smp_mb() */ /* smp_rmb() */
off = LOAD fifo->in + off off = LOAD fifo->out + off
/* memcpy */ /* memcpy */
/* smp_wmb() */ /* smp_mb() */
STORE fifo->in += off STORE fifo->out += off
两个函数的内存访问的会产生干扰的操作位于 kfifo_len() 中,假设现在是单生产者单消费者模式,考虑下面的情况
kfifo_in()
t1 out = LOAD fifo->out
t2 /* smp_rmb() */
t3 len = LOAD fifo->in - out
t4 /* smp_mb() */ kfifo_out()
t5 off = LOAD fifo->in + off out = LOAD fifo->out
t6 /* memcpy */ /* smp_rmb() */
t7 /* smp_wmb() */ len = LOAD fifo->in - out
t8 STORE fifo->in += off /* smp_rmb() */
t9 off = LOAD fifo->out + off
t10 /* memcpy */
t11 /* smp_mb() */
t12 STORE fifo->out += off
kfifo_out()
t1 out = LOAD fifo->out
t2 /* smp_rmb() */
t3 len = LOAD fifo->in - out
t4 /* smp_rmb() */ kfifo_in()
t5 off = LOAD fifo->out + off out = LOAD fifo->out
t6 /* memcpy */ /* smp_rmb() */
t7 /* smp_mb() */ len = LOAD fifo->in - out
t8 STORE fifo->out += off /* smp_mb() */
t9 off = LOAD fifo->in + off
t10 /* memcpy */
t11 /* smp_wmb() */
t12 STORE fifo->in += off
后执行的函数在 t8 时刻,实际上内存已经写入或者读出,但是 in 和 out 并没有发生改变就被另外一个函数读取。
而这并不会产生错误,但是写入或者读出的数据都比实时的数据偏小,这也是 kfifo 的高明之处。
如果出队入队的操作特别频繁的话,对结果没影响。
若是要保持实时的顺序,即 t6 -> t8,一个函数的 memcpy 操作立刻对另一个 memcpy 可见,所以需要采取一些辅助措施来保证这个效果。
来源:https://www.cnblogs.com/shuqin/p/11391536.html