Linux内核的驱动异步io机制

  1. 什么叫异步io,阻塞io如果应用程序读取时时条件不满足,则会阻塞,进程随眠,效率低下,而异步io可以实现应该程序发送读请求的之后继续执行后面的代码,当条件满足的时候内核会发信号让应用程序可以处理,提高效率。
  2. 函数说明:
应用层:
1. flag = fcntl(fd,F_GETFL,0);		
   功能描述:先获得文件描述符的属性
2. flag |= FASYNC ;
   功能描述:修改文件描述符的属性(异步io)
3. fcntl(fd,F_SETFL,flag);		
   功能描述:设置属性成异步io,会调用内核的fasync函数
4. fcntl(fd,F_SETOWN,getpid());		
   功能描述:使内核收到数据后发送SIGIO(29号)信号给本进程
5. signal(29,myfun);
   功能描述:应用程序收到信号后的处理函数
内核层:
6. fasync_helper(fd, pfile, mode, &pfasync);
   功能描述:使文件具备异步通知功能
7. kill_fasync(&pfasync,29,POLL_IN);			
   功能描述:发送信号给用户程序 
  1. 代码实现:
A.cpp在发送读请求后编进入死循环,当B.cpp执行以后内核会发信号给A.cpp处理
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include "linux/cdev.h"
#include "linux/kdev_t.h"
#include "linux/fs.h"
#include "asm/uaccess.h"
#include "linux/sched.h"

MODULE_LICENSE ("GPL");

struct cdev  myuart; 
int major = 200;
int minor = 2;

dev_t  dev_id;
char kernel_buf[64] = {0};
struct fasync_struct  *pfasync;		1.实例化结构体
struct file_operations  var; 

int myopen(struct inode *pinode, struct file *pfile)
{
    printk(KERN_INFO "myopen run\n");
    return 0;
}
int myclose(struct inode *pinode, struct file *pfile)
{
     printk(KERN_INFO "myclose run\n");
     return 0;
}
ssize_t myread(struct file *pfile, char __user *buf, size_t len, loff_t *off)
{
      int ret = 0;     
      printk(KERN_INFO "myread run\n");
      ret = copy_to_user(buf,kernel_buf,19);
      
      return 19-ret;
}

ssize_t mywrite(struct file *pfile, const char __user *buf, size_t len, loff_t *off) 
{
     int ret;
     ret = copy_from_user(kernel_buf,buf,len) ; 
     printk(KERN_INFO "mywrite fun run ret = %d\n",ret) ;  
     kill_fasync(&pfasync,29,POLL_IN);			2.发送信号给用户程序 
     return 30;
}
int myfasync(int fd, struct file *pfile, int mode)
{
    printk(KERN_INFO "myfasync function run\n");
    fasync_helper(fd, pfile, mode, &pfasync);		2.使文件具备异步通知机制
    return 0;
}
static int  __init hello_init (void)
{
        
        int ret = 0;
        int ret1;

        dev_id = MKDEV(major,minor) ;  
        ret = register_chrdev_region(dev_id,1, "uart");
        if(ret == -1) 
        {
             printk(KERN_INFO "dev_id = %d can't use \n",major);
             ret1 = alloc_chrdev_region(&dev_id,minor,1, "uart");
             if(ret1 == -1)
             {
                  printk(KERN_INFO "dev_id error \n");
                  return -1;
             }
             else
             {
                  printk(KERN_INFO "major = %d \n", MAJOR(dev_id)); 
             }   
        }
        else
        {
            printk(KERN_INFO "major = %d can use \n",major);
        }
        var.open = myopen;
        var.release = myclose;
        var.write = mywrite;
        var.read = myread;
        var.fasync = myfasync;		2.要用到fasync函数使得设备具有异步通知功能
        cdev_init(&myuart,&var); 
 
        cdev_add(&myuart,dev_id,1);
	printk (KERN_INFO "driver init");
	return 0;
}

static void  __exit hello_exit (void)
{
      unregister_chrdev_region(dev_id, 1);
      cdev_del(&myuart);
      printk (KERN_INFO "driver exit");
}

module_init (hello_init);
module_exit (hello_exit);

A.c代码,发送读取请求
#include "stdio.h"
#include "fcntl.h"
#include "stdlib.h"
#include "unistd.h"
int fd;
void myfun(int sig)		5.应用程序收到信号后的处理函数
{
    char buf[64] = {0};
    if(sig == 29)
    {
         read(fd,buf,64) ;
         printf("buf = %s\n",buf) ;      
    }
    return ;
}
int main()
{
    int flag;
    int len;
    int i = 0;
    fd  = open("./kkk.c",O_RDWR,0777);
    if(fd == -1)
    {
        printf("open error\n");
        return -1;
    }
  		
    flag = fcntl(fd,F_GETFL,0);		1.先获得文件描述符的属性
    flag |= FASYNC ;		2.修改文件描述符的属性(异步io)
    fcntl(fd,F_SETFL,flag);		3.设置属性成异步io,会调用内核的fasync函数
    fcntl(fd,F_SETOWN,getpid());		4.使内核收到数据后发送SIGIO(29号)信号给本进程
    signal(29,myfun);		5.应用程序收到信号后的处理函数
    while(1)
    {
        i ++;
        printf("process some things  i = %d\n",i);
        sleep(1);
    }
    close(fd);
    return 0;
}

B.c代码,向内核写入数据
#include "stdio.h"
#include "fcntl.h"
#include "stdlib.h"
#include "unistd.h"
#include "string.h"
int main()
{
    int fd;
    int len;
    char buf[64] = {0};
    fd  = open("./kkk.c",O_RDWR,0777);
    if(fd == -1)
    {
        printf("open error\n");
        return -1;
    }
    while(1)
    {
        printf("please input send to kernel data\n");
        scanf("%s",buf);
        len = write(fd,buf,64);
        memset(buf,0,64);
     }
    
    close(fd);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
我可以为您提供一个简单的基于Linux异步IO驱动程序范例。这个例子演示了如何使用异步IO驱动程序在Linux内核中使用I/O, 并且可以说是一个非常简单的实现。但是需要注意的是,这个例子并不是用来在实际应用中使用的,而是用来理解和学习异步IOLinux中的使用方法。以下是基于Linux异步IO驱动程序范例代码: ```c #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/cdev.h> #include <linux/version.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/slab.h> #include <asm/uaccess.h> #include <linux/wait.h> #include <linux/poll.h> #include <linux/async.h> #include <linux/ioctl.h> #define DEVICE_NAME "my_device" // 设备名称 #define MSG_BUFFER_LEN 2048 // 消息缓冲区长度 #define MAJOR_NUM 101 // 设备主设备号 #define MSG_START_CMD 0x00 // 消息开始命令 #define MSG_STOP_CMD 0x01 // 消息停止命令 static int major_num; // 设备主设备号 static char *msg_buffer; static struct class *my_class; static struct device *my_device; static struct cdev my_cdev; static DECLARE_WAIT_QUEUE_HEAD(read_wq); // 定义等待队列 read_wq static struct async_struct my_async; typedef struct { unsigned char command; unsigned int data_len; void * data; // 存储数据 } command_t; // 驱动程序打开函数 static int my_device_open(struct inode *inode, struct file *file) { return 0; } // 驱动程序关闭函数 static int my_device_release(struct inode *inode, struct file *file) { return 0; } // 驱动程序读函数 static ssize_t my_device_read(struct file *filp, char __user *buf, size_t len, loff_t *off) { int size; if( async_scheduled(&my_async) ) // 如果异步请求完成 { size = async_error(&my_async); // 获取异步请求结果 if(size < 0) // 如果请求错误 return size; // 如果请求成功 copy_to_user(buf, my_async.buf, size); // 将缓冲区中的数据传递给用户空间 async_done(&my_async, size); // 完成异步请求 return size; } if(wait_event_interruptible(read_wq, async_scheduled(&my_async))) // 等待异步请求 return -ERESTARTSYS; // 如果被中断则返回错误 size = async_error(&my_async); // 获取异步请求结果 if(size < 0) // 如果请求错误 return size; // 如果请求成功 copy_to_user(buf, my_async.buf, size); // 将缓冲区中的数据传递给用户空间 async_done(&my_async, size); // 完成异步请求 return size; } // 驱动程序写函数 static ssize_t my_device_write(struct file *filp, const char __user *buf, size_t len, loff_t *off) { int size; unsigned int data_len; command_t cmd; cmd.data = kmalloc(MSG_BUFFER_LEN, GFP_KERNEL); if (copy_from_user(&cmd, buf, sizeof(cmd))) // 从用户空间中拷贝数据 goto ERROR_SYS; if (cmd.data_len > MSG_BUFFER_LEN) // 请求的数据长度过长 goto ERROR_CMD; if (copy_from_user(cmd.data, buf + sizeof(cmd), cmd.data_len)) // 从用户空间中拷贝数据 goto ERROR_SYS; size = async_read(my_async.q, cmd.command, cmd.data, cmd.data_len, 0); // 发送异步请求 if(size < 0) // 如果请求错误 goto ERROR_SYS; kfree(cmd.data); return cmd.data_len + sizeof(unsigned char) + sizeof(unsigned int); ERROR_CMD: kfree(cmd.data); return -EINVAL; // 命令错误 ERROR_SYS: kfree(cmd.data); return -EFAULT; // 拷贝数据错误 } // 驱动程序控制命令函数 static long my_device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { if (cmd == MSG_STOP_CMD) // 发送停止异步请求命令 { async_stop(&my_async.q); return 0; } return -ENOTTY; } // 驱动程序操作函数 static struct file_operations my_device_fops = { .owner = THIS_MODULE, .open = my_device_open, .release = my_device_release, .read = my_device_read, .write = my_device_write, .unlocked_ioctl = my_device_ioctl, .compat_ioctl = my_device_ioctl, }; // 驱动程序初始化函数,注册设备 static int __init my_device_init(void) { int res; dev_t dev; // 申请设备号 res = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME); if (res < 0) { printk(KERN_ERR "Failed to allocate char device region\n"); return res; } // 获得设备主设备号 major_num = MAJOR(dev); msg_buffer = kmalloc(MSG_BUFFER_LEN, GFP_KERNEL); if (!msg_buffer) // 申请内核缓冲区失败 goto ERR_KMALLOC; async_init(&my_async, msg_buffer, MSG_BUFFER_LEN, GFP_KERNEL); // 初始化异步请求结构体 cdev_init(&my_cdev, &my_device_fops); // 初始化设备 res = cdev_add(&my_cdev, MKDEV(major_num, 0), 1); // 加入驱动程序 if (res < 0) { printk(KERN_ERR "Couldn't add the device to the system\n"); goto ERR_CDEV_ADD; } my_class = class_create(THIS_MODULE, DEVICE_NAME); // 创建设备类 if (IS_ERR(my_class)) // 如果创建设备类失败 goto ERR_CLASS_CREATE; my_device = device_create(my_class, NULL, MKDEV(major_num, 0), NULL, DEVICE_NAME); // 创建设备 if (IS_ERR(my_device)) // 如果创建设备失败 goto ERR_DEVICE_CREATE; printk(KERN_INFO "Device registered with major number %d\n", MAJOR(dev)); return 0; ERR_DEVICE_CREATE: class_destroy(my_class); ERR_CLASS_CREATE: cdev_del(&my_cdev); ERR_CDEV_ADD: kfree(msg_buffer); ERR_KMALLOC: unregister_chrdev_region(MKDEV(major_num, 0), 1); return res; } // 驱动程序卸载函数,注销设备 static void __exit my_device_exit(void) { device_destroy(my_class, MKDEV(major_num, 0)); class_unregister(my_class); class_destroy(my_class); cdev_del(&my_cdev); kfree(msg_buffer); unregister_chrdev_region(MKDEV(major_num, 0), 1); async_release(&my_async.q); // 释放异步请求队列资源 printk(KERN_INFO "Device unregistered\n"); } MODULE_LICENSE("GPL"); MODULE_AUTHOR("CSDN"); MODULE_DESCRIPTION("Driver for my device"); module_init(my_device_init); module_exit(my_device_exit); ``` 这是一个非常简单的基于Linux异步IO驱动程序范例,该范例可以与用户空间应用程序交互来实现I/O操作。由于涉及异步IO操作,需要相应的理解和学习才能正确使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值