全部博文(1493)
分类: 嵌入式
2013-03-18 08:52:24
一、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、再或上异步通知的属性FASYNC。fcntl(fd, F_SETFL, oflags | FASYNC);
5、每当FASYNC标志发生改变时,驱动程序中的fasync()函数将得以执行。而驱动中的fasync()函数内容相当于初始化async_queue结构体指针。
6、While(1),最后进入死循环,仅为保持进程不终止,如果没有这个死循环,程序会 立即执行完毕。
7、内核中。定义异步通知函数globalmem_fasync。记住:要放在 globalmem_fasync(-1,filp,0);globalmem_release函数----删除的上面。 P178
8、当设备资源可以获得时,调用kill_fasync()函数激发相应的信号。
Read:read通知写, if(dev->async_queue)
kill_fasync(&dev->async_queue,SIGIO,POLL_OUT);
记住:屏蔽掉等待队列,若不屏蔽,则会读写读写,不停。
write:write通知读: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,就跳到中断处理函数,进行写操作。
2、write写触发读:当我们写入数据后,就会调用写函数,。。同上,触发读信号。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标志的设置,并在资源科获得时释放信号。