I am studying the implementation of kfifo.c in Linux kernel version 2.6. I don’t quite understand how the queue in
and out
pointers wrap around to handle the remainder.
For example, kfifo.c
use l = fifo->in - fifo->out
to calculate the space used in the queue. Suppose in
= 0, out
= 1, fifo->size
= 8. And both in
and out
are unsigned int, both are 32 bits. So l = fifo->in - fifo->out
will be 32 bits 1 represents 4294967295. But the actual used space in queue is l = (fifo->in - fifo->out) & (fifo->size-1) = 7
So my problem is Why l
doesn’t AND with the fifo->size-1
?
unsigned int __kfifo_out_peek(struct __kfifo *fifo,
void *buf, unsigned int len)
{
unsigned int l;
l = fifo->in - fifo->out;
if (len > l)
len = l;
kfifo_copy_out(fifo, buf, len, fifo->out);
return len;
}
static void kfifo_copy_out(struct __kfifo *fifo, void *dst,
unsigned int len, unsigned int off)
{
unsigned int size = fifo->mask + 1;
unsigned int esize = fifo->esize;
unsigned int l;
off &= fifo->mask;
if (esize != 1) {
off *= esize;
size *= esize;
len *= esize;
}
l = min(len, size - off);
memcpy(dst, fifo->data + off, l);
memcpy(dst + l, fifo->data, len - l);
/*
* make sure that the data is copied before
* incrementing the fifo->out index counter
*/
smp_wmb();
}
Also, I have another question is the implementation of kfifo_unused
in kfifo.c
. fifo->mask+1
represents fifo->size
. Also assuming in = 0
, out = 1
, fifo->size = 8
. The following code will return 9
, But actually the usused space should be 1.
static inline unsigned int kfifo_unused(struct __kfifo *fifo)
{
return (fifo->mask + 1) - (fifo->in - fifo->out);
}