字符设备驱动第八课----异步通知(信号驱动IO)
来源:互联网 发布:java分布式系统架构 编辑:程序博客网 时间:2024/05/10 05:11
概述
类比运用程序中的kill-----signal,在运用程序中常常一个进程用kill(pid,sig)向另一进程发信号,另一个进程用signal(sig,handler)绑定相应的处理函数,实现了异步通知。今天要讲的就是:运用程序要读,但它并不知道啥时候有东西可读,用read()阻塞去读显然效率不高,read()配合IO多路复用非阻塞一直在那里轮询的话效率也不好。这里采用的办法是:驱动层有数据可读的时候kill一个SIGIO信号给运用层,运用层收到SIGIO信号后调用预先绑定好的处理函数把数据读走。
若还迷糊概念,请看看这位大神的清晰讲解:
信号驱动IO与异步通知
<include/linux/fs.h>struct file_operations { int (*open) (struct inode *, struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, loff_t, loff_t, int datasync); //用于异步通知 ...}
<include/linux/fs.h>struct fasync_struct { spinlock_t fa_lock; int magic; int fa_fd; struct fasync_struct *fa_next; /* singly linked list */ struct file *fa_file; struct rcu_head fa_rcu;};
/** 功能: 得到异步通知结构。根据mod,将异步通知结构体加入链表* 运用程序端调用这些函数改变标志和owner时就调用了这个底层实现。* fcntl(STDIN_FILENO,F_SETOWN,getpid());* oflags = fcntl(STDIN_FILENO,F_GETFL);* fctcl(STDIN_FILENO,F_SETFL,oflags | FASYNC);* 输入参数: fd: 文件描述符* filp: file结构体指针* 输出参数:fapp:得到的异步通知结构体 */int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
/* * 功能:通过异步通知结构发信号,此信号发出时运用端就会收到SGIO信号,就会回调预先绑定的处理函数。 * 参数:struct fasync_struct **fp: 异步通知结构 * int signo: 信号(SIGIO) * int events: 事件:POLLIN、POLLOUT */void kill_fasync(struct fasync_struct **fp, int sig, int band)
范例:
1.驱动端:
#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/cdev.h>#include <linux/fs.h>#include <linux/errno.h>#include <asm/current.h>#include <linux/sched.h>#include <linux/uaccess.h>#include <linux/poll.h>#include <asm/atomic.h>#include <linux/mutex.h>#include <linux/wait.h>#include <linux/device.h>static struct class *cls = NULL;static int major = 0;static int minor = 0;const int count = 6;#define DEVNAME "demo"static struct cdev *demop = NULL;static atomic_t tv;static wait_queue_head_t wq;static struct fasync_struct *fasync = NULL;//定义异步通知结构体#define KMAX 1024static char kbuf[KMAX];static int counter = 0;//打开设备static int demo_open(struct inode *inode, struct file *filp){ //get major and minor from inode printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n", imajor(inode), iminor(inode), __FILE__, __func__, __LINE__); if(!atomic_dec_and_test(&tv)){ atomic_inc(&tv); return -EBUSY; } memset(kbuf, 0, KMAX); counter = 0; return 0;}//关闭设备static int demo_release(struct inode *inode, struct file *filp){ //get major and minor from inode printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n", imajor(inode), iminor(inode), __FILE__, __func__, __LINE__); atomic_inc(&tv); return 0;}//读设备//ssize_t read(int fd, void *buf, size_t count)static ssize_t demo_read(struct file *filp, char __user *buf, size_t size, loff_t *offset){ int err = 0; struct inode *inode = filp->f_path.dentry->d_inode; //获取文件的inod号 //get major and minor from inode printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n", imajor(inode), iminor(inode), __FILE__, __func__, __LINE__); if(!counter){ if(filp->f_flags & O_NONBLOCK){ return -EAGAIN; } err = wait_event_interruptible(wq, (0 != counter));//睡在条件上的等待队列 if(err){ //没东西可读,睡 return err; } } if(counter < size){ size = counter; } if(copy_to_user(buf, kbuf, size)){ return -EAGAIN; } counter = 0; return size;}//写设备static ssize_t demo_write(struct file *filp, const char __user *buf, size_t size, loff_t *offset){ struct inode *inode = filp->f_path.dentry->d_inode; //get major and minor from inode printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n", imajor(inode), iminor(inode), __FILE__, __func__, __LINE__); if(size > KMAX){ return -ENOMEM; } if(copy_from_user(kbuf, buf, size)){ return -EAGAIN; } counter = size; wake_up_interruptible(&wq);//广播唤醒等待队列 kill_fasync(&fasync, SIGIO, POLLIN);//向fasync结构体发信号, //与fasync关联的进程(通过fcntl(...,pid)系列函数关联)就会收到SIGIO信号 return size;}/* IO多路复用支持*/static unsigned int demo_poll(struct file *filp, struct poll_table_struct *pts){ unsigned int mask = 0; struct inode *inode = filp->f_path.dentry->d_inode; //get major and minor from inode printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n", imajor(inode), iminor(inode), __FILE__, __func__, __LINE__); poll_wait(filp, &wq, pts);//io多路复用支持,只有等待队列中有就绪的事件才会往下走,否则阻塞 if(counter){ mask = (POLLIN | POLLRDNORM);//返回,告诉运用层的poll函数:就绪事件是输入事件 } return mask;}/*异步通知接口函数,应用层调fcntl()时调到此函数*/static int demo_fasync(int fd, struct file *filp, int mode){ struct inode *inode = filp->f_path.dentry->d_inode; //get major and minor from inode printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n", imajor(inode), iminor(inode), __FILE__, __func__, __LINE__); return fasync_helper(fd, filp, mode, &fasync);//根据mod,将异步通知结构体加入链表 //或者从链表中移除。得到信息并填充到fasync结构体中}static struct file_operations fops = { .owner = THIS_MODULE, .open = demo_open, .release= demo_release, .read = demo_read, .write = demo_write, .poll = demo_poll, .fasync = demo_fasync,};static int __init demo_init(void){ dev_t devnum; int ret, i; struct device *devp = NULL; //get command and pid printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n", current->comm, current->pid, __FILE__, __func__, __LINE__); //1. alloc cdev obj demop = cdev_alloc(); if(NULL == demop){ return -ENOMEM; } //2. init cdev obj cdev_init(demop, &fops); ret = alloc_chrdev_region(&devnum, minor, count, DEVNAME); if(ret){ goto ERR_STEP; } major = MAJOR(devnum); //3. register cdev obj ret = cdev_add(demop, devnum, count); if(ret){ goto ERR_STEP1; } cls = class_create(THIS_MODULE, DEVNAME); if(IS_ERR(cls)){ ret = PTR_ERR(cls); goto ERR_STEP1; } for(i = minor; i < (count+minor); i++){ devp = device_create(cls, NULL, MKDEV(major, i), NULL, "%s%d", DEVNAME, i); if(IS_ERR(devp)){ ret = PTR_ERR(devp); goto ERR_STEP2; } } // init atomic_t atomic_set(&tv, 1); init_waitqueue_head(&wq);//初始化等待队列 //get command and pid printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - ok.\n", current->comm, current->pid, __FILE__, __func__, __LINE__); return 0;ERR_STEP2: for(--i; i >= minor; i--){ device_destroy(cls, MKDEV(major, i)); } class_destroy(cls);ERR_STEP1: unregister_chrdev_region(devnum, count);ERR_STEP: cdev_del(demop); //get command and pid printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - fail.\n", current->comm, current->pid, __FILE__, __func__, __LINE__); return ret;}static void __exit demo_exit(void){ int i; //get command and pid printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - leave.\n", current->comm, current->pid, __FILE__, __func__, __LINE__); for(i=minor; i < (count+minor); i++){ device_destroy(cls, MKDEV(major, i)); } class_destroy(cls); unregister_chrdev_region(MKDEV(major, minor), count); cdev_del(demop);}module_init(demo_init);module_exit(demo_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Farsight");MODULE_DESCRIPTION("Demo for kernel module");
2.运用程序端:
#include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <poll.h>#include <signal.h>#include <errno.h>int fd = -1;void handler(int sig)//信号处理函数,与signal绑定的{ struct pollfd pfd = { .fd = fd, .events = POLLIN, }; int ret = poll(&pfd, 1, ~0);//监控pfd,最大文件描述符1,永不超时 if(0 >= ret){ //没一个就绪则阻塞,只要其中有任意一个就绪就往下走 perror("poll"); return; }#define MAX 1024 char buf[MAX]; memset(buf, 0, MAX); if(0 > read(fd, buf, MAX)){ perror("read"); }else{ printf("RD: %s\n", buf); }}int main(int num, char *argv[]){ if(2 != num){ printf("Usage: %s /dev/devfile\n", argv[0]); return -1; } fd = open(argv[1], O_RDWR|O_NONBLOCK); if(0 > fd){ printf("pid = %d, %s\n", getpid(), (char *)strerror(errno)); return -1; } signal(SIGIO, handler);//绑定信号处理函数 fcntl(fd, F_SETOWN, getpid());//关联收发,设置对应文件的拥有者是本进程,这样接下来才能进行信号的收发 int flag = fcntl(fd, F_GETFL);//读取对应文件描述符上的flg信息 flag |= O_ASYNC; fcntl(fd, F_SETFL, flag); //设置对应文件描述符上的flg信息,使其支持异步通知 //这个函数实质上最终调用的是操作方法集中的.fasync标准接口,对应到驱动层中的相应函数 while(1){ printf("---------w: 1----------\n"); #define MAX 1024 char buf[MAX]; fgets(buf, MAX, stdin); write(fd, buf, strlen(buf)); } close(fd); return 0;}
0 0
- 字符设备驱动第八课----异步通知(信号驱动IO)
- 字符设备驱动-异步通知
- Linux字符设备驱动之异步通知
- linux字符设备驱动之异步通知
- Linux的异步通知字符设备驱动
- linux字符设备驱动-异步通知笔记
- Linux字符设备驱动之异步通知
- linux字符设备驱动-异步通知
- 字符设备驱动之Buttons-异步通知(fasync)
- 字符设备驱动之笔记-异步通知(fasync)
- 字符设备驱动之笔记-异步通知(fasync)
- linux设备驱动中的异步通知与异步IO
- Linux设备驱动中的异步通知和异步IO
- 字符设备驱动第八课------读写锁
- 字符设备驱动第八课----自旋锁
- 字符设备驱动第八课----互斥锁
- 字符设备驱动第八课----信号量
- 字符设备驱动学习笔记----异步通知机制
- 无功功率等概念的定义 引自《三相电路瞬时无功功率理论的研究》--王兆安
- 第 12 章 - 11 扩展管理器
- Android Annotations在studio上的配置
- 基于TMS320C6455的千兆以太网设计
- 串口简易程序
- 字符设备驱动第八课----异步通知(信号驱动IO)
- android pm指令使用
- 文章标题struct对齐方式
- [C语言][LeetCode][414]Third Maximum Number
- 厉害了我滴哥,原来验证码是这么造出来的!
- 前端面试注意
- Ibatis返回结果集
- 使用Maven管理进行多模块开发
- Oracle数据库中几种非常有用的函数(with……as等)