为什么kfifo在某些博客中是循环队列

时间:2018-11-26 07:54:25

标签: c linux linux-kernel

kfifo是Circlar队列吗?

在Circlar队列中,WIKI(https://en.wikipedia.org/wiki/Circular_buffer)说:“ 端到端连接。”。但在linux-4.16.12 \ lib \ kfifo.c

int __kfifo_init(struct __kfifo *fifo, void *buffer,
        unsigned int size, size_t esize)
{
    size /= esize;

    size = roundup_pow_of_two(size);

    fifo->in = 0;
    fifo->out = 0;
    fifo->esize = esize;
    fifo->data = buffer;

    if (size < 2) {
        fifo->mask = 0;
        return -EINVAL;
    }
    fifo->mask = size - 1;

    return 0;
}

我找不到起始指针指向结束指针,所以:

1)kfifo是否为Circlar队列?

2)是的话,如何证明呢?

1 个答案:

答案 0 :(得分:1)

Wikipedia page you mentioned声明循环缓冲区的行为就像端对端连接。实际上,循环缓冲区只是一个固定长度的数组,其中两个索引指针(通常称为headtailinout)代表“边界”。为了避免在缓冲区边界之外进行写操作,对这些索引的所有算术运算都应在缓冲区的modulo长度处进行。

通常,指针的含义是:

  • headin索引,指示下一个可用于写入的插槽,并且
  • tailout索引,指示最后读取(“已删除”)的插槽。

还有两个边界状态:

  • 如果tail等于head,则缓冲区为空。
  • 如果增加tail的模缓冲区长度将使tailhead相等,则缓冲区已满。

大多数实现将使用以下方法之一将索引保持在缓冲区范围内:

// check if index overflowed and reset
int fifo_increment_index(struct fifo *fifo, int index)
{
     index = index + 1; 
     if (index > fifo->capacity)
         index = 0;
     return index;
}

// use the modulo operator (slower due to division,
// although it avoids branching)
int fifo_increment_index(struct fifo *fifo, int index)
{
     index = (index + 1) % fifo->capacity; // modulo
     return index;
}

// use a bitwise mask (in most cases the fastest approach),
// but works ONLY if capacity is a power of 2
int fifo_increment_index(struct fifo *fifo, int index)
{
     // if capacity is 1024 (0x400), then
     // mask will be 1023 (0x3FF)

     index = (index + 1) & fifo->mask; // bitwise and
     return index;
}

Linux kfifo使用最后一种方法(按位屏蔽),这就是为什么它总是ensures that the capacity is a power of two放在init函数(size = roundup_pow_of_two(size))中的原因。

但是,它不会立即更改索引,而是会在每次访问缓冲区时将其屏蔽:

#define __KFIFO_PEEK(data, out, mask) ( (data)[(out) & (mask)] )
#define __KFIFO_POKE(data, in, mask, val) ( (data)[(in) & (mask)] = (unsigned char)(val) )

对于uint8_t缓冲区,__KFIFO_PEEK宏基本上是:

static inline uint8_t kfifo_peek(struct __kfifo *fifo)
{
     int index = fifo->out & fifo->mask;
     return fifo->data[index];
}