kfifo的使用

linux的kfifo有以下注意点
1.当向fifo填充数据时称作put,这将会累加in字段,当向fifo取数据时称作get,这将会累加out字段。
2.对于只有一个生产者和一个消费者情形,可以不用对加锁,如有多个则需要加锁
3.当fifo缓冲区的size时2的次方时,kfifo->in % kfifo->size 可以转化为 kfifo->in & (kfifo->size – 1),否则不能。
4.in和out字段需要定义成无符号字段,当增加到最大值时,产生溢出从0就开始,以此循环使用
5.对于多个cpu,在每次读写in、out字段之前需要加内存屏障,1个cpu则不需要

下面是单核、一个生产者和一个消费者情形、buff size不是2的次方、1个cpu kfifo的例子

//filename:kfifo.c
#include "kfifo.h"

#define min(a,b) ((a) < (b) ? (a):(b))

int kFifoInit(kfifo_t *fifo, unsigned char *buffer, unsigned int size)
{
    if (!fifo)
        return -1;

    if(!buffer)
        return -1;

    fifo->buffer = buffer;
    fifo->size = size;
    fifo->in = fifo->out = 0;

    return 0;
}

unsigned int kFifoPut(kfifo_t *fifo, unsigned char *buffer, unsigned int len)
{
	unsigned int l;
 
	len = min(len, fifo->size - fifo->in + fifo->out);/*可能是缓冲区的空闲长度或者要写长度*/
 
	/* first put the data starting from fifo->in to buffer end*/
	//l = min(len, fifo->size - (fifo->in & (fifo->size -1)));
	l = min(len, fifo->size - (fifo->in % (fifo->size)));
	
	//memcpy((fifo->buffer + (fifo->in & (fifo->size -1))), buffer, l);
	memcpy((fifo->buffer + (fifo->in % (fifo->size))), buffer, l);
 
	/* then put the rest (if any) at the beginning of the buffer*/
	memcpy(fifo->buffer, buffer + l, len - l);

	fifo->in += len;
 
	return len;
}


unsigned int kFifoGet(kfifo_t *fifo, unsigned char *buffer, unsigned int len)
{
    unsigned int l;
 
    len = min(len, fifo->in - fifo->out); /*可读数据*/
 
    /* first get the data from fifo->out until the end of the buffer*/
    //l = min(len, fifo->size - (fifo->out & (fifo->size -1)));
    l = min(len, fifo->size - (fifo->out % (fifo->size)));
    //memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size -1)), l);
     memcpy(buffer, fifo->buffer + (fifo->out % (fifo->size)), l);
	
    /* then get the rest (if any) from the beginning of the buffer*/
    memcpy(buffer + l, fifo->buffer, len - l);
 
    fifo->out += len;
 
    return len;
}


unsigned int kFifoPeer(kfifo_t *fifo, unsigned char *buffer, unsigned int len)
{
    unsigned int l;
 
    len = min(len, fifo->in - fifo->out); /*可读数据*/
 
    /* first get the data from fifo->out until the end of the buffer*/
    //l = min(len, fifo->size - (fifo->out & (fifo->size -1)));
	l = min(len, fifo->size - (fifo->out % (fifo->size)));
    //memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size -1)), l);
	memcpy(buffer, fifo->buffer + (fifo->out % (fifo->size)), l);
 
    /* then get the rest (if any) from the beginning of the buffer*/
    memcpy(buffer + l, fifo->buffer, len - l);
  
    return len;
}


void kFifoReset(kfifo_t *fifo)
{
    fifo->in = fifo->out = 0;
}

unsigned int kFifoLen(kfifo_t *fifo)
{
    return fifo->in - fifo->out;
}


unsigned int kFifoAviable(kfifo_t *fifo)
{
    return fifo->size - kFifoLen(fifo);
}

//full 1
unsigned int kFifoFull(kfifo_t *fifo)
{
    return fifo->size == kFifoLen(fifo);
}

//empty 1
unsigned int kFifoEmpty(kfifo_t *fifo)
{
    return fifo->in == fifo->out;
}

//filename:kfifo.h
#ifndef _KFIFO_H_
#define _KFIFO_H_

#include "soc_types.h"
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>

typedef struct kfifo 
{
    unsigned char *buffer;/* the buffer holding the data*/
    unsigned int size;/* the size of the allocated buffer*/
    unsigned int in;/* data is added at offset (in % size)*/
    unsigned int out;/* data is extracted from off. (out % size)*/
}kfifo_t;

extern int kFifoInit(kfifo_t *fifo, unsigned char *buffer, unsigned int size);
extern unsigned int kFifoPut(kfifo_t *fifo, unsigned char *buffer, unsigned int len);
extern unsigned int kFifoGet(kfifo_t *fifo, unsigned char *buffer, unsigned int len);
extern unsigned int kFifoPeer(kfifo_t *fifo, unsigned char *buffer, unsigned int len);
extern void kFifoReset(kfifo_t *fifo);
extern unsigned int kFifoLen(kfifo_t *fifo);
extern unsigned int kFifoAviable(kfifo_t *fifo);
extern unsigned int kFifoFull(kfifo_t *fifo); //full 1
extern unsigned int kFifoEmpty(kfifo_t *fifo); //empty 1

#endif
您可以参考以下代码实现一个简单的Linux kfifo demo: ``` #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/slab.h> #include <linux/kfifo.h> #define FIFO_SIZE 1024 MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("A Linux kfifo demo"); static char *fifo_buffer; static struct kfifo my_fifo; static int my_open(struct inode *inode, struct file *file) { printk(KERN_INFO "my device opened\n"); return 0; } static int my_close(struct inode *inode, struct file *file) { printk(KERN_INFO "my device closed\n"); return 0; } static ssize_t my_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { ssize_t ret; if (kfifo_is_empty(&my_fifo)) { return -EAGAIN; } ret = kfifo_to_user(&my_fifo, user_buf, count, ppos); if (ret) { printk(KERN_INFO "Read %ld bytes\n", (long)ret); } else { printk(KERN_ERR "Failed to read\n"); } return ret; } static ssize_t my_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { ssize_t ret; if (kfifo_avail(&my_fifo) < count) { return -ENOMEM; } ret = kfifo_from_user(&my_fifo, user_buf, count, ppos); if (ret) { printk(KERN_INFO "Wrote %ld bytes\n", (long)ret); } else { printk(KERN_ERR "Failed to write\n"); } return ret; } static struct file_operations my_fops = { .owner = THIS_MODULE, .open = my_open, .release = my_close, .read = my_read, .write = my_write, }; static int __init my_init(void) { int ret; fifo_buffer = kmalloc(FIFO_SIZE, GFP_KERNEL); if (!fifo_buffer) { return -ENOMEM; } ret = kfifo_init(&my_fifo, fifo_buffer, FIFO_SIZE); if (ret) { kfree(fifo_buffer); return ret; } ret = register_chrdev(0, "my_device", &my_fops); if (ret < 0) { kfifo_free(&my_fifo); kfree(fifo_buffer); return ret; } printk(KERN_INFO "my device registered with major number %d\n", ret); return 0; } static void __exit my_exit(void) { unregister_chrdev(0, "my_device"); kfifo_free(&my_fifo); kfree(fifo_buffer); printk(KERN_INFO "my device unregistered\n"); } module_init(my_init); module_exit(my_exit); ``` 该代码实现了一个简单的字符设备,它使用了Linux内核中提供的kfifo数据结构来实现队列的功能,用户可以通过该设备的文件描述符进行读写操作,读取数据会将队列中的数据写入用户缓冲区,写入数据会将用户缓冲区中的数据写入队列中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值