第四讲 Linux内核KFIFO的使用

四、内核KFIFO

4.1、概述

  • 在驱动编程中,经常会遇到异步数据处理的情况,比如采用中断或定时器处理数据输入输出等情况

  • 此时数据的采集与处理往往不同步,于是驱动编程中数据采集方需要将采集的数据暂时放到一个缓冲区中,使用方在需要处理数据时从缓冲区中将数据读出

  • 驱动编程中常采用队列这种数据结构来实现整个过程,我们可以选择自己编写一个队列,也可以利用内核中现有队列kfifo来实现。

4.2、使用过程

  1. 定义KFIFO变量;
  2. 为KFIFO开辟空间;
  3. 把数据写入KFIFO;
  4. 从KFIFO读出数据;
  5. 释放KFIFO。

4.3、KFIFO相关的API

#include <linux/kfifo.h>	//头文件包含

//kfifo结构体类型
struct kfifo{
	unsigned char *buffer;	//存放数据的缓存区
	unsigned int size;	//buffer空间大小
	unsigned int in;	//指向buffer队头
	unsigned int out;	//指向buffer队尾
};

image-20220327154232736

1. kfifo申请分配空间:

/*
 *gfp_mask申请内存的flags:
 *GFP_KERNEL 在分配的空间时可以参与进程调度
 *GFP_ATOMIC 在分配空间时,必须一次性完成
 */
int kfifo_alloc(struct kfifo *fifo,unsigned int size, gfp_t gfp_mask)

void kfifo_free(struct kfifo*fifo) //释放空间

2. 内核空间内存的申请和释放

/* kmalloc分配的空间在物理内存和虚拟内存上均连续*/
void *kmalloc(size_t size,gfp_t gfp);
void kfree(void *p);

/*分配的内存空间在虚拟内存上连续,在物理内存上不一定连续*/
void* vmalloc(unsigned long size);
void vfree(void*ptr);

3. kfifo相关操作:

  • 将数据放入kfifo内,返回值为实际写入的数据长度:

    unsigned int kfifo_in(struct kfifo *fifo,const void *from, unsigned int len);
    
  • 从kfifo读取数据,返回值为实际读出的数据长度:

    unsigned int kfifo_out(struct kfifo *fifo, void *to, unsigned int len);
    
  • 获取fifo内的已用数据个数 :

    unsigned int kfifo_len(struct kfifo *fifo);
    
  • 获取fifo总大小:

    unsigned int kfifo_size(struct kfifo *fifo);
    
  • 检查kfifo是否为空:

    int kfifo_is_empty(struct kfifo *fifo);
    
  • 检查kfifo是否为满:

    int kfifo_is_full(struct kfifo *fifo);
    
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
您可以参考以下代码实现一个简单的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
发出的红包

打赏作者

Leon_George

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值