Linux内核的驱动异步io机制

    技术2022-07-11  72

    什么叫异步io,阻塞io如果应用程序读取时时条件不满足,则会阻塞,进程随眠,效率低下,而异步io可以实现应该程序发送读请求的之后继续执行后面的代码,当条件满足的时候内核会发信号让应用程序可以处理,提高效率。函数说明: 应用层: 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); 功能描述:发送信号给用户程序 代码实现: 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; }
    Processed: 0.010, SQL: 9