Chinaunix首页 | 论坛 | 博客
  • 博客访问: 685089
  • 博文数量: 209
  • 博客积分: 26
  • 博客等级: 民兵
  • 技术积分: 326
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-21 09:29
文章分类

全部博文(209)

文章存档

2015年(6)

2014年(40)

2013年(154)

2012年(11)

我的朋友

分类: 嵌入式

2013-03-08 14:59:31

原文地址:异步I/O--信号 作者:小霸王88

一、IO分类:

a) 阻塞I0------>阻塞I/O意味着一直等待设备可访问后再访问。

b) 非阻塞IO----->意味着使用poll()查询设备是否可访问。

c) IO复用(轮询select---.>算非阻塞?

d) 异步IO(信号驱动的IO)--设备通知自身可访问,实现了异步I/O.

二、异步通知:一旦设备就绪,则主动通知应用程序。由内核向应用-发信号,类似中断.类似于我们之前的同步。一边有事发生,马上通知另一边(内核空间和用户空间),两边几乎同步。而同步类似我们之前的异步,是交替运行的。

注:SIGKILL用来立即结束程序的运行本信号不能被阻塞、处理和忽略

三、重点关注的信号:

a) SIGIO   键盘输入或者当文件可读、写===IO  键盘输入==可读  文件发出来的。。

b) SIGINT  终端中断 ctrl+c

c) SIGQUIT 终端退出 ctrl+\

一个信号被捕获:当一个信号到达时有相应的代码处理它。如果一个信号没有被这个进程捕获,内核采用默认行为处理。

注:键盘输入,可读。因为有东西输入,就可以读。                  进程间通讯IPC

实现原理:main函数中设置signal(SIGIO, io_handler);说明当捕捉到信号SIGIO(读写都是这个),执行处理函数io_handler.当设置完属性,然后再设置一下,由本进程来接收fcntl(fd, F_SETOWN, getpid())。再通过fcntl(fd, F_SETFL, oflags | FASYNC)设置完后,具有异步FASYNC功能后,在键盘或者其他(read或者write)就是IO操作都是当做一个异步信号的产生。假设我们键盘按下,就是产生一个异步信号,内核中的globalmem_fasync()函数则被调用执行。不关用户层的事,相当于按键中断一样,有按键按下,就有中断产生一样。当globalmem_fasync()执行完后,if(dev->async_queue)就不为空,调用kill_fasync()函数来激发相应的信号。假设键盘按下,则是可读,则调用read函数,之后释放异步信号,用户层signal收到后执行对应的信号处理函数。

四:实现原理:

1、应用层:设置信号处理函数,当信号SIGIO发出时,去处理。

2、设置属性.fcntl(fd, F_SETOWN, getpid());其中F_SETOWN设置属性,把fd发出的信 号由getpid()来收,即当前进程,因为一个信号发出来说不定有很多进程接收到。.没有 这一步,内核不会知道应该将信号发给哪个进程。键盘,有东西输入,可读。

3、设置前,先获取当前的状态,即掩码。oflags = fcntl(fd, F_GETFL);

4、再或上异步通知的属性FASYNCfcntl(fd, F_SETFL, oflags | FASYNC);

5、每当FASYNC标志发生改变时,驱动程序中的fasync()函数将得以执行。而驱动中的fasync()函数内容相当于初始化async_queue结构体指针。

6、While1),最后进入死循环,仅为保持进程不终止,如果没有这个死循环,程序会 立即执行完毕。

7、内核中。定义异步通知函数globalmem_fasync记住:要放在 globalmem_fasync(-1,filp,0);globalmem_release函数----删除的上面。 P178

8、当设备资源可以获得时,调用kill_fasync()函数激发相应的信号。

Readread通知写, if(dev->async_queue)

kill_fasync(&dev->async_queue,SIGIO,POLL_OUT);

记住:屏蔽掉等待队列,若不屏蔽,则会读写读写,不停。

writewrite通知读:if(dev->async_queue)

kill_fasync(&dev->async_queue,SIGIO,POLL_IN);

可不必屏蔽等待队列

9、信号处理函数执行,所对应要通知的对象。

可读===POLL_IN----个人理解,有东西进来,in,说明可以读了。

可写===POLL_OUT=====个人理解,有东西出去,out,说明可以写了

1、read读触发写:当我们键盘输入数据后,说明有数据输入,可读,就会调用读函数,在读函数中要产生异步写的信号。所以要先判断dev->async_queue(异步结构体指针,用于读)。当该数不为空的时候,产生真正的异步写信号给用户层kill_fasync(&dev->async_queue,SIGIO,POLL_OUT)

),poll_out对应写,则用户层捕捉到信号SIGIO,就跳到中断处理函数,进行写操作。

2write写触发读:当我们写入数据后,就会调用写函数,。。同上,触发读信号。POLL_IN读信号给用户层。

用户空间中能处理一个设备释放的信号:

1、通过F_SETOWN  IO控制命令设置设备文件的拥有者为本进程,这样设备驱动发 出的信号才能被本进程接收到哦。

2、通过F_SETFL  IO控制命令设置文件支持FASYNC,即异步通知模式。

3、通过signal()函数连接信号和信号处理函数。

内核驱动为了能支持异步通知机制:

1、支持F_SETOWN 命令,能在这个控制命令处理中设置filp->owmer为对应进程ID。不过此项工作已由内核完成,设备驱动无需处理。

2、支持F_SETFL 命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行,因此,驱动中应该实现fasync()函数。

3、在设备资源科获得时,调用kill_fasync()函数激发相应的信号。

总结:设备驱动和用户空间分别完成以下工作:

用户空间设置文件的拥有者、FASYNC标志及捕捉信号,内核空间相应对文件的拥有者,FASYNC标志的设置,并在资源科获得时释放信号。

阅读(857) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~