队列 -- fifo

linux 内核通用队列称为 kfifo.  定义于<linux/kfifo.h>中

linux 的 kfifo 和多数其他队列一样,也提供了两个主要函数,enqueue(入队列) 和 dequeue(出队列)

kfifo 对象 维护了两个偏移量,入口偏移 和 出口偏移。

入口偏移 指下一次入队列时的位置

出口偏移 指下一次出队列的位置。

出口偏移 总是小于等于 入口偏移,否则就意味着要出队列的元素根本没有入队列。

1. 创建队列:

a. kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask) : 动态创建, (常用),

该函数创建并初始化一个大小为size的kfifo. gfp_mask  用来标识分配队列。

/**
 * kfifo_alloc - allocates a new FIFO internal buffer
 * @fifo: the fifo to assign then new buffer
 * @size: the size of the buffer to be allocated, this have to be a power of 2.
 * @gfp_mask: get_free_pages mask, passed to kmalloc()
 *
 * This function dynamically allocates a new fifo internal buffer
 *
 * The size will be rounded-up to a power of 2.
 * The buffer will be release with kfifo_free().
 * Return 0 if no error, otherwise the an error code
 */
int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask)
{
	unsigned char *buffer;

	/*
	 * round up to the next power of 2, since our 'let the indices
	 * wrap' technique works only in this case.
	 */
	if (!is_power_of_2(size)) {  //size必须是2的指数次幂
		BUG_ON(size > 0x80000000);
		size = roundup_pow_of_two(size); //如果不是整成是~
	}

	buffer = kmalloc(size, gfp_mask);
	if (!buffer) {
		_kfifo_init(fifo, NULL, 0);
		return -ENOMEM;
	}

	_kfifo_init(fifo, buffer, size); //初始化fifo

	return 0;
}

static void _kfifo_init(struct kfifo *fifo, void *buffer,
		unsigned int size)
{
	fifo->buffer = buffer;
	fifo->size = size;

	kfifo_reset(fifo);
}

/**
 * kfifo_reset - removes the entire FIFO contents
 * @fifo: the fifo to be emptied.
 */
static inline void kfifo_reset(struct kfifo *fifo)
{
	fifo->in = fifo->out = 0;
}

例:

struct kfifo fifo;

int ret;

ret = kfifo_alloc(&fifo, PAGE_SIZE, GFP_KERNEL);

if(ret)

    return ret;

//fifo 现在是一个大小为PAGE_SIZE的队列

b. kfifo_init(struct kfifo *fifo, void *buffer, unsigned int size):

该函数创建并初始化一个kfifo,它将使用 由 buffer 指向的 大小为size 的内存

/**
 * kfifo_init - initialize a FIFO using a preallocated buffer
 * @fifo: the fifo to assign the buffer
 * @buffer: the preallocated buffer to be used.
 * @size: the size of the internal buffer, this has to be a power of 2.
 *
 */
void kfifo_init(struct kfifo *fifo, void *buffer, unsigned int size)
{
	/* size must be a power of 2 */
	BUG_ON(!is_power_of_2(size)); //size必须是2的指数次幂

	_kfifo_init(fifo, buffer, size);
}
EXPORT_SYMBOL(kfifo_init);

c. 静态创建kfifo,(不大常用)

DECLARE_KFIFO(name, size) --- 将创建一个名字为name,大小为size的kfifo对象。

/**
 * DECLARE_KFIFO - macro to declare a kfifo and the associated buffer
 * @name: name of the declared kfifo datatype
 * @size: size of the fifo buffer. Must be a power of two.
 *
 * Note1: the macro can be used inside struct or union declaration
 * Note2: the macro creates two objects:
 *  A kfifo object with the given name and a buffer for the kfifo
 *  object named name##kfifo_buffer
 */
#define DECLARE_KFIFO(name, size) \
union { \
	struct kfifo name; \
	unsigned char name##kfifo_buffer[size + sizeof(struct kfifo)]; \
}
 INIT_KFIFO(name) --- 初始化kfifo

/**
 * INIT_KFIFO - Initialize a kfifo declared by DECLARE_KFIFO
 * @name: name of the declared kfifo datatype
 */
#define INIT_KFIFO(name) \
	name = __kfifo_initializer(sizeof(name##kfifo_buffer) - \
				sizeof(struct kfifo), \
				name##kfifo_buffer + sizeof(struct kfifo))
/*
 * Macros for declaration and initialization of the kfifo datatype
 */

/* helper macro */
#define __kfifo_initializer(s, b) \
	(struct kfifo) { \
		.size	= s, \
		.in	= 0, \
		.out	= 0, \
		.buffer = b \
	}

DEFINE_KFIFO(name, size)  =DECLARE_KFIFO(name, size) +  INIT_KFIFO(name)

/**
 * DEFINE_KFIFO - macro to define and initialize a kfifo
 * @name: name of the declared kfifo datatype
 * @size: size of the fifo buffer. Must be a power of two.
 *
 * Note1: the macro can be used for global and local kfifo data type variables
 * Note2: the macro creates two objects:
 *  A kfifo object with the given name and a buffer for the kfifo
 *  object named name##kfifo_buffer
 */
#define DEFINE_KFIFO(name, size) \
	unsigned char name##kfifo_buffer[size]; \
	struct kfifo name = __kfifo_initializer(size, name##kfifo_buffer)

2. kfifo_in(struct kfifo *fifo, const void *from, unsigned int len) : 入队列操作:

该函数把from指针所指向的 len字节长度的 数据拷贝到fifo所指队列中。

成功则返回推入的字节长度。

/**
 * kfifo_in - puts some data into the FIFO
 * @fifo: the fifo to be used.
 * @from: the data to be added.
 * @len: the length of the data to be added.
 *
 * This function copies at most @len bytes from the @from buffer into
 * the FIFO depending on the free space, and returns the number of
 * bytes copied.
 *
 * Note that with only one concurrent reader and one concurrent
 * writer, you don't need extra locking to use these functions.
 */
unsigned int kfifo_in(struct kfifo *fifo, const void *from,
				unsigned int len)
{
	len = min(kfifo_avail(fifo), len);

	__kfifo_in_data(fifo, from, len, 0);
	__kfifo_add_in(fifo, len);
	return len;
} 
3. kfifo_out(struct kfifo *fifo, void *to, unsigned int len) : 出队列操作:

该函数从 fifo所指向的队列中 拷贝出 长度为len字节的数据 到 to所指的缓冲 中。

成功返回拷贝数据的长度。

/**
 * kfifo_out - gets some data from the FIFO
 * @fifo: the fifo to be used.
 * @to: where the data must be copied.
 * @len: the size of the destination buffer.
 *
 * This function copies at most @len bytes from the FIFO into the
 * @to buffer and returns the number of copied bytes.
 *
 * Note that with only one concurrent reader and one concurrent
 * writer, you don't need extra locking to use these functions.
 */
unsigned int kfifo_out(struct kfifo *fifo, void *to, unsigned int len)
{
	len = min(kfifo_len(fifo), len);

	__kfifo_out_data(fifo, to, len, 0);
	__kfifo_add_out(fifo, len);

	return len;
}
EXPORT_SYMBOL(kfifo_out);
数据被出队列之后,就不再存于队列当中,这是常用队列操作。如果仅仅想“偷窥”下队列中的数据,不想删除它,可以用:

kfifo_out_peek(struct kfifo *fifo, void *to, unsigned int len, unsigned offset)

/**
 * kfifo_out_peek - copy some data from the FIFO, but do not remove it
 * @fifo: the fifo to be used.
 * @to: where the data must be copied.
 * @len: the size of the destination buffer.
 * @offset: offset into the fifo
 *
 * This function copies at most @len bytes at @offset from the FIFO
 * into the @to buffer and returns the number of copied bytes.
 * The data is not removed from the FIFO.
 */
unsigned int kfifo_out_peek(struct kfifo *fifo, void *to, unsigned int len,
			    unsigned offset)
{
	len = min(kfifo_len(fifo), len + offset);

	__kfifo_out_data(fifo, to, len, offset);
	return len;
}
EXPORT_SYMBOL(kfifo_out_peek);
4. 获取队列长度:

a. kfifo_size(struct kfifo *fifo) : kfifo 队列总体长度

/**
 * kfifo_size - returns the size of the fifo in bytes
 * @fifo: the fifo to be used.
 */
static inline __must_check unsigned int kfifo_size(struct kfifo *fifo)
{
	return fifo->size;
}
b. kfifo_len(struct kfifo *fifo) :kfifo队列中已推入数据大小

/**
 * kfifo_len - returns the number of used bytes in the FIFO
 * @fifo: the fifo to be used.
 */
static inline unsigned int kfifo_len(struct kfifo *fifo)
{
	register unsigned int	out;

	out = fifo->out;
	smp_rmb();
	return fifo->in - out;
}
c. kfifo_avail(struct kfifo *fifo) : kfifo队列中,还有多少可用空间

/**
 * kfifo_avail - returns the number of bytes available in the FIFO
 * @fifo: the fifo to be used.
 */
static inline __must_check unsigned int kfifo_avail(struct kfifo *fifo)
{
	return kfifo_size(fifo) - kfifo_len(fifo);
}
d. kfifo_is_empty(struct kfifo *fifo) :是否为空

/**
 * kfifo_is_empty - returns true if the fifo is empty
 * @fifo: the fifo to be used.
 */
static inline __must_check int kfifo_is_empty(struct kfifo *fifo)
{
	return fifo->in == fifo->out;
}
e. kfifo_is_full(struct kfifo *fifo) : 是否已满

/**
 * kfifo_is_full - returns true if the fifo is full
 * @fifo: the fifo to be used.
 */
static inline __must_check int kfifo_is_full(struct kfifo *fifo)
{
	return kfifo_len(fifo) == kfifo_size(fifo);
}
5. kfifo_reset(struct kfifo *fifo) : 重置队列,即清空队列中的内容

/**
 * kfifo_reset - removes the entire FIFO contents
 * @fifo: the fifo to be emptied.
 */
static inline void kfifo_reset(struct kfifo *fifo)
{
	fifo->in = fifo->out = 0;
}
kfifo_free(struct kfifo *fifo) : 撤销队列, 与kfifo_alloc对应。

/**
 * kfifo_free - frees the FIFO internal buffer
 * @fifo: the fifo to be freed.
 */
void kfifo_free(struct kfifo *fifo)
{
	kfree(fifo->buffer);
	_kfifo_init(fifo, NULL, 0);
}
EXPORT_SYMBOL(kfifo_free);
如果是kfifo_init()创建的,还需要释放相关缓冲(buffer)

6. kfifo使用举例:

a. 将0-31压入名为fifo的队列:

unsigned int i;

for(i = 0; i < 32; i++)  //将0 - 31 压入名为fifo的队列中

    kfifo_in(fifo, &i, sizeof(i));
b. 查看一下队列的第一个元素是不是0:
unsigned int val;

int ret;

ret = kfifo_out_peek(fifo, &val, sizeof(val), 0);

if (ret != sizeof(val))

     return -EINVAL;

printk(KERN_INFO, "%u\n",val);

c. 出队列,并打印kfifo中的所有元素,即将上面的0-31 打印出来。

while(kfifo_avail(fifo)) {

    unsigned int val;

    int ret;

    ret = kfifo_out(fifo, &val, sizeof(val));

    if(ret != sizeof(val))

        return -EINVAL;

    printk(KERN_INFO, "%u\n", val);

}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值