Smart20学习记录----异步通知
异步通知:
阻塞与非阻塞访问、poll()函数提供了较好地解决设备访问的机制(应用程序主动访问)
异步通知:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上“中断”的概念,比较准确的称谓是“信号驱动的异步 I/O”
阻塞 I/O 意味着一直等待设备可访问后再访问,非阻塞 I/O 中使用 poll()意味着查询设备是否可访问,而异步通知则意味着设备通知自身可访问,实现了异步 I/O。由此可见,这几种方式 I/O可以互为补充。
阻塞、非阻塞 I/O、异步通知本身没有优劣,应该根据不同的应用场景合理选择。
linux异步通知编程:
1.信号的接受:
在用户程序中,为了捕获信号,可以使用 signal()函数来设置对应信号的处理函数:
void (*signal(int signum, void (*handler))(int)))(int);
该函数原型较难理解,它可以分解为:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler));
第一个参数指定信号的值,第二个参数指定针对前面信号值的处理函数,若为SIG_IGN,表示 忽略该信号;若为 SIG_DFL,表示采用系统默认方式处理信号;若为用户自定义的函数,则信号 被捕获到后,该函数将被执行。 如果 signal()调用成功,它返回最后一次为信号 signum 绑定的处理函数 handler 值,失败则返 回 SIG_ERR。
使用信号实现异步通知的应用程序实例:
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <stdio.h>
4 #include <fcntl.h>
5 #include <signal.h>
6 #include <unistd.h>
7 #define MAX_LEN 100
8 void input_handler(int num)
9 {
10 char data[MAX_LEN];
11 int len;
12
13 /* 读取并输出 STDIN_FILENO 上的输入 */
14 len = read(STDIN_FILENO, &data, MAX_LEN);
15 data[len] = 0;
16 printf("input available:%s\n", data);
17 }
18
19 main()
20 {
21 int oflags;
22
23 /* 启动信号驱动机制 */
24 signal(SIGIO, input_handler);
25 fcntl(STDIN_FILENO, F_SETOWN, getpid());
26 oflags = fcntl(STDIN_FILENO, F_GETFL);
27 fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC);
28
29 /* 最后进入一个死循环,仅为保持进程不终止,如果程序中
30 没有这个死循会立即执行完毕 */
31 while (1);
32 }
上述代码 24 行为 SIGIO 信号安装 input_handler()作为处理函数,第 25 行设置本进程为 STDIN_FILENO 文件的拥有者(owner),没有这一步内核不会知道应该将信号发给哪个进程。而 为了启用异步通知机制,还需对设备设置 FASYNC 标志,26~27 行代码实现此目的。
由此可见,为了在用户空间中能处理一个设备释放的信号,它必须完成 3 项工作。 (1)通过 F_SETOWN IO 控制命令设置设备文件的拥有者为本进程,这样从设备驱动发出的 信号才能被本进程接收到。 (2)通过 F_SETFL IO 控制命令设置设备文件支持 FASYNC,即异步通知模式。 (3)通过 signal()函数连接信号和信号处理函数。
相关链接:http://blog.csdn.net/bailyzheng/article/details/7463775
信号的释放:
在设备驱动和应用程序的异步通知交互中,仅仅在应用程序端捕获信号是不够的,因为信号 没有的源头在设备驱动端。因此,应该在合适的时机让设备驱动释放信号,在设备驱动程序中增 加信号释放的相关代码。 为了使设备支持异步通知机制,驱动程序中涉及 3 项工作。
(1)支持 F_SETOWN 命令,能在这个控制命令处理中设置 filp->f_owner 为对应进程 ID。不 过此项工作已由内核完成,设备驱动无需处理。
(2)支持 F_SETFL 命令的处理,每当FASYNC 标志改变时,驱动程序中的fasync()函数将得 以执行。因此,驱动中应该实现 fasync()函数。 (
3)在设备资源可获得时,调用 kill_fasync()函数激发相应的信号
设备驱动中异步通知编程比较简单,主要用到一项数据结构和两个函数。数据结构是
fasync_struct 结构体,两个函数分别是:
处理 FASYNC 标志变更的。
int fasync_helper(int fd, struct file *filp, int mode, struct fasync_struct **fa);
释放信号用的函数。
void kill_fasync(struct fasync_struct **fa, int sig, int band);
相关驱动:
#include <linux/module.h>//support module load and unload
#include <linux/types.h>//special type definition,like dev_t off_t defined by typedef
#include <linux/fs.h>//struct file_operations
#include <linux/errno.h>//return value
#include <linux/mm.h>//memory mannage ,include kmalloc.kfree and so on
#include <linux/sched.h>//process schedule
#include <linux/init.h>//
#include <linux/cdev.h>//char device structure definition
#include <linux/io.h>//io operation function ,like ioremap,iowrite
#include <linux/poll.h> MODULE_AUTHOR("qigaohua") ;
MODULE_LICENSE("Dual BSD/GPL") ; #define GLOBALFIFO_SIZE 0x1000 //1M
#define CLEAR_ALL 0x01 //clear fifo
#define GLOBALFIFO_MAJOR 0//major device No static int globalfifo_major = GLOBALFIFO_MAJOR ;
/*define globalfifo structure*/
struct globalfifo_dev {
struct cdev dev ;
unsigned int current_len ;
unsigned char mem[GLOBALFIFO_SIZE] ;
struct semaphore sem ;
wait_queue_head_t r_wait ;
wait_queue_head_t w_wait ;
struct fasync_struct fasync_queue;
} ;
struct globalfifo_dev *globalfifo_devp = NULL; static int globalfifo_open(struct inode *inode, struct file *filp)
{
filp->private_data = globalfifo_devp ;
return ;
}
static int globalfifo_release(struct inode *inode ,struct file *filp)
{
globalfifo_fasync(-, filp, );
return ;
} static int globalfifo_ioctl(struct inode *inode, struct file *filp,
int cmd, unsigned long arg)
{
struct globalfifo_dev *dev = filp->private_data ;
switch (cmd)
{
case CLEAR_ALL:
/*note:down_intterruptible is more suitable,why?*/
down_interruptible(&dev->sem) ;
dev->current_len = ;
memset(dev->mem,,GLOBALFIFO_SIZE) ;
up(&dev->sem) ;
printk(KERN_INFO "clear globalfifo successfully!\n") ;
break ;
default:
printk(KERN_INFO "invalid command!\n") ;
return -EINVAL ;
}
} static unsigned int globalfifo_poll(struct file *filp, poll_table *wait)
{
unsigned int mask = ;
struct globalfifo_dev *dev = filp->private_data ; down_interruptible(&dev->sem) ; poll_wait(filp,&dev->r_wait,wait) ;
poll_wait(filp,&dev->w_wait,wait) ; if(dev->current_len != )
{
mask |= POLLIN | POLLRDNORM ;
}
if(dev->current_len< GLOBALFIFO_SIZE )
{
mask |= POLLOUT | POLLWRNORM ;
}
up(&dev->sem) ;
return mask ;
}
static ssize_t globalfifo_read(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
int ret ;
struct globalfifo_dev *dev = filp->private_data ;
DECLARE_WAITQUEUE(wait,current) ;
down_interruptible(&dev->sem) ;
add_wait_queue(&dev->r_wait,&wait) ;
if(dev->current_len == )
{
if( filp->f_flags & O_NONBLOCK)
{
ret = -EAGAIN ;
goto out ;
}
__set_current_state(TASK_INTERRUPTIBLE) ;
up(&dev->sem) ;
schedule() ;
if(signal_pending(current))
{
ret = - ERESTARTSYS ;
goto out2 ;
}
down_interruptible(&dev->sem) ;
}
if(count>dev->current_len)
{
count = dev->current_len ;
}
if(copy_to_user(buf,dev->mem,count))
{
ret = -EFAULT ;
goto out ;
}else
{
memcpy(dev->mem,dev->mem+count,dev->current_len-count) ;
dev->current_len -= count ;
printk(KERN_INFO "read %d bytes(s),current_len:%d\n",
count,dev->current_len) ;
wake_up_interruptible(&dev->w_wait) ;
ret = count ;
}
out:
up(&dev->sem) ;
out2:
remove_wait_queue(&dev->w_wait,&wait) ;
set_current_state(TASK_RUNNING) ;
return ret ;
} static int globalfifo_fasync(int fd, struct file *filp, int mode)
{
struct globalfifo_dev *dev = file->private_data;
return fasync_helper(fd, filp, mode, &dev->fasync_queue);
} static ssize_t globalfifo_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
struct globalfifo_dev *dev = filp->private_data ;
int ret = - ;
DECLARE_WAITQUEUE(wait,current) ; down_interruptible(&dev->sem) ;
add_wait_queue(&dev->w_wait,&wait) ; if(dev->current_len == GLOBALFIFO_SIZE)
{
if(filp->f_flags & O_NONBLOCK)
{
ret = -EAGAIN ;
goto out ;
}
__set_current_state(TASK_INTERRUPTIBLE) ;
up(&dev->sem) ; schedule() ;
if(signal_pending(current))
{
ret = -ERESTARTSYS ;
goto out2 ;
}
down_interruptible(&dev->sem) ;
} if(count>GLOBALFIFO_SIZE-dev->current_len)
{
count = GLOBALFIFO_SIZE - dev->current_len ;
}
if(copy_from_user(dev->mem+dev->current_len,buf,count))
{
ret = - EFAULT ;
goto out ;
}else
{
dev->current_len += count ;
printk(KERN_INFO "written %d bytes(s),cuurent_len:%d",
count , dev->current_len ) ;
wake_up_interruptible(&dev->r_wait) ;
if(dev->fasync_queue)
kill_fasync(&dev->fasync_queue, SIGIO, POLLIN);
ret = count ;
}
out:
up(&dev->sem) ;
out2:
remove_wait_queue(&dev->w_wait,&wait) ;
set_current_state(TASK_RUNNING) ;
return ret ;
}
static const struct file_operations globalfifo_fops = {
.owner = THIS_MODULE ,
.open = globalfifo_open ,
.read = globalfifo_read ,
.write = globalfifo_write ,
.ioctl = globalfifo_ioctl ,
.poll = globalfifo_poll ,
.fasync = globalfifo_fasync,
.release = globalfifo_release ,
} ;
int __init globalfifo_init(void)
{
int ret ;
dev_t devno = MKDEV(globalfifo_major, ) ;
if(globalfifo_major)
{
ret = register_chrdev_region(devno,,"globalfifo") ;
}else
{
ret = alloc_chrdev_region(&devno,,,"globalfifo") ;
globalfifo_major = MAJOR(devno) ;
}
if(ret<){
printk(KERN_INFO "apply for device No failed! major:%d,minor:%d\n",MAJOR(devno),MINOR(devno)) ;
return ret ;
}
globalfifo_devp = kmalloc(sizeof(struct globalfifo_dev),GFP_KERNEL) ;
if(!globalfifo_devp){
ret = - ENOMEM ;
goto fail_malloc ;
} memset(globalfifo_devp, , sizeof(struct globalfifo_dev)) ; cdev_init(&globalfifo_devp->dev, &globalfifo_fops) ; globalfifo_devp->dev.owner = THIS_MODULE ;
globalfifo_devp->dev.ops = &globalfifo_fops ;
if(cdev_add(&globalfifo_devp->dev, devno,)) {
printk(KERN_NOTICE "add cdev failed!\n") ;
} INIT_MUTEX(&globalfifo_devp->sem) ;
init_waitqueue_head(&globalfifo_devp->r_wait) ;
init_waitqueue_head(&globalfifo_devp->w_wait) ;
printk(KERN_INFO "init globalfifo device successfully!\n" ) ;
return ;
fail_malloc:
unregister_chrdev_region(devno,) ;
return ret ;
}
void __exit globalfifo_exit(void)
{
if(globalfifo_devp != NULL ){
cdev_del(&globalfifo_devp->dev) ;
kfree(globalfifo_devp) ;
unregister_chrdev_region(MKDEV(globalfifo_major,),) ;
}
printk(KERN_INFO "unload globalfifo device successfully!\n") ;
}
//module_param(globalfifo_major, int , S_IRUGO) ; module_init(globalfifo_init) ;
module_exit(globalfifo_exit) ;
来自《Linux设备驱动开发详解》
Smart20学习记录----异步通知的更多相关文章
- 嵌入式Linux驱动学习之路(十三)按键驱动-异步通知
之前的按键方式: 查询: 极度占用CPU资源 中断: 在读的时候产生休眠,在没有信号的时候永远不会返回. poll机制: 在中断的基础上加上超时时间. 异步通知就是通过信号来传送. 首先在应用程序中有 ...
- Linux学习 :按键信号 之 异步通知
一.异步通知概念: 异步通知是指:一旦设备就绪,则主动通知应用程序,应用程序根本就不需要查询设备状态,类似于中断的概念,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是异步的,一个进 ...
- NodeJS 学习记录
这里是我学习NodeJs的学习记录 URL:网址解析的好帮手 URL,URI 首先,URI是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源.而URL是u ...
- Linux之异步通知20160702
异步通知,主要说的是使用信号的方式,同时使用信号也是实现进程之间通信的一种方式. 多的不说,我们直接看代码: 首先应用程序的: #include <sys/types.h> #includ ...
- UWP学习记录12-应用到应用的通信
UWP学习记录12-应用到应用的通信 1.应用间通信 “共享”合约是用户可以在应用之间快速交换数据的一种方式. 例如,用户可能希望使用社交网络应用与其好友共享网页,或者将链接保存在笔记应用中以供日后参 ...
- arm驱动linux异步通知与异步IO【转】
转自:http://blog.csdn.net/chinazhangzhong123/article/details/51638793 <[ arm驱动] linux异步通知与 异步IO> ...
- Linux设备驱动中的异步通知与异步I/O
异步通知概念: 异步通知的意识是,一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上的“中断”概念,比较准确的称谓是“信号驱动的异步IO”,信号是在软件层次 ...
- 支付宝接口使用文档说明 支付宝异步通知(notify_url)与return_url.
支付宝接口使用文档说明 支付宝异步通知(notify_url)与return_url. 现支付宝的通知有两类. A服务器通知,对应的参数为notify_url,支付宝通知使用POST方式 B页面跳转通 ...
- 【转】BLE 学习记录
原文网址:http://m.blog.csdn.net/blog/chiooo/43985401 BLE 学习记录 ANROID BLE 开发,基于 bluetoothlegatt 分析 mBluet ...
随机推荐
- http请求详解
GET GET方法意思是获取被请求URI(Request-URI)指定的信息(以实体的格式).如果请求URI涉及到一个数据生成过程,那么这个过程生成的数据应该被作为实体在响应中返回而不是过程的源文本, ...
- 表单重置reset
最近一直在做各种页面的“增删改查”,只是在做新增功能的时候,自己一直在使用 reset来清空form表单,原以为这样子的清空方法是万无一失的,可惜最终还是在进行“修改”操作完了之后再“新增”的时候,就 ...
- 百度Tera数据库介绍——类似cassandra,levelDB
转自:https://my.oschina.net/u/2982571/blog/775452 设计背景 百度的链接处理系统每天处理万亿级的超链数据,在过去,这是一系列Mapreduce的批量过程,对 ...
- BZOJ3993 [SDOI2015]星际战争
二分答案...然后最大流验证是否可行... 没了,好水啊QAQ /************************************************************** Prob ...
- mysql启动报错
查看报错日志: 131023 15:02:59 [ERROR] Can't start server: Bind on TCP/IP port: No such file or directory13 ...
- java之进制转换
[转载]晨风�0�5�0�2�0�1�6�6 2014年03月08日 于 爱Java 发表 众所周知.程序世界计算机中采用的是二进制,一个数字可以用任意进制表示.所以看一个数据值的同时.还要观察它的进 ...
- hduacm 5255
http://acm.hdu.edu.cn/showproblem.php?pid=5255 枚举a和c 求解b #include <cstdio> #include <cstri ...
- javascript——拖拽(完整兼容代码)
拖拽,是JS经常会用到的效果,在网上有很多的这样那样的拖拽效果,但其中往往大多有各种各养的问题,功能不全,无法兼容,而且修改的时候 也是十分麻烦. 其实拖拽的原理很简单,无非是鼠标的三个动作的解析,以 ...
- ioinc
ioinc setup sassnpm installionic serve cordova plugin add cordova-plugin-crosswalk-webview 十.开发流程 1. ...
- ubuntu安装vim
1.安装 sudo apt-get install vim-gtk 2.安装完成之后,在命令行敲入vi,按“tab”键,可以看到,已经有vim命令的存在,安装成功. 3.配置 sudo vim /et ...