【Linux 驱动】第六章 高级字符驱动程序操作----异步通知
2012-04-13 17:04
323 查看
一,概念
异步通知:一旦设备就绪,则主动通知应用程序,应用程序根本就不需要查询设备状态。(类似于中断)信号是异步的,一个进程不必通过任何操作来等待信号的到达
在linux中,异步通知是使用信号来实现的,而在linux,大概有30种信号,比如大家熟悉的ctrl+c的sigint信号,进程能够忽略或者捕获除过SIGSTOP和SIGKILL的全部信号,当信号背捕获以后,有相应的函数来处理它。
二,应用程序角度考虑
应用程序为了启用文件的异步通知机制,必须执行两个步骤:
1)指定一个进程作为文件的"属主",进程可以使用fcntl执行F_SETOWN命令(此时进程id号被保存在filp->f_owner中),目的是为了让内核知道应该通知哪个进程。
2)用户通过fcntl的F_SETFL命令设置FASYNC标志。
执行完上述两个步骤后,输入文件可以在数据到达时请求发送一个ISGIO信号(驱动程序发送),该信号发送到存放在filp->f_owner中的进程。
如下示例代码启用stdin文件的异步通知机制:
signal(SIGIO,&input_handler);
fcntl(STDIN_FILENO,F_SETOWN,getpid());
oflags = fcntl(STDIN_FILENO,F_GETFL);
fcntl(STDIN_FILENO,F_SETFL,oflags | FASYNC);
应用程序中还有两点注意:应用程序不是所有设备都支持异步通知,通常应用程序假设只有套接字和终端才有异步通知能力;如果有多个文件可以异步通知输入的进程,应用程序需要借助poll或者select来确定输入的来源(利用FD_ISSET来判断)。
三,驱动程序角度考虑
那么驱动程序如何来实现异步信号呢?
内核已经提供了很方便的函数给我们使用,为了实现异步信号,驱动程序需要做三件事情:
1)实现fasync方法:该方法也只需要做一步,调用内核提供的fasync_helper函数,如下是scullp设备提供的实现代码:
static int scull_p_fasync(int fd, struct file *filp,int mode)
{
struct scull_pipe *dev = filp->private_data;
return fasync_helper(fd,filp,mode,&dev->async_queue);
}
2)当数据到达时,需要实现异步通知,这时需要调用kill_fasync,当数据可读时,此时需要通知应用程序数据可读,如下是scullp设备提供的代码:
if(dev->async_queue)
kill_fasync(&dev->async_queue,SIGIO,POLL_IN);
如果是为写入提供异步信号,kill_fasync必为模式调用POLL_OUT。
3)在文件关闭时必须调用fasync方法,以便从活动的异步读取进程列表中删除该文件,所有在close方法中有如下调用:
sucll_p_fasync(-1,filp,0);
四,llseeek实现
llseek方法对应lseek和llseek系统调用,该方法通过直接修改filp->f_pos执行定位操作,filp->f_pos记录的文件的读写位置,为了让lseek系统调用正确工作,read/write方法必须通过更新它们收到的偏移量参数来配合。在scull设备中的该方法实现如下:
异步通知:一旦设备就绪,则主动通知应用程序,应用程序根本就不需要查询设备状态。(类似于中断)信号是异步的,一个进程不必通过任何操作来等待信号的到达
在linux中,异步通知是使用信号来实现的,而在linux,大概有30种信号,比如大家熟悉的ctrl+c的sigint信号,进程能够忽略或者捕获除过SIGSTOP和SIGKILL的全部信号,当信号背捕获以后,有相应的函数来处理它。
二,应用程序角度考虑
应用程序为了启用文件的异步通知机制,必须执行两个步骤:
1)指定一个进程作为文件的"属主",进程可以使用fcntl执行F_SETOWN命令(此时进程id号被保存在filp->f_owner中),目的是为了让内核知道应该通知哪个进程。
2)用户通过fcntl的F_SETFL命令设置FASYNC标志。
执行完上述两个步骤后,输入文件可以在数据到达时请求发送一个ISGIO信号(驱动程序发送),该信号发送到存放在filp->f_owner中的进程。
如下示例代码启用stdin文件的异步通知机制:
signal(SIGIO,&input_handler);
fcntl(STDIN_FILENO,F_SETOWN,getpid());
oflags = fcntl(STDIN_FILENO,F_GETFL);
fcntl(STDIN_FILENO,F_SETFL,oflags | FASYNC);
应用程序中还有两点注意:应用程序不是所有设备都支持异步通知,通常应用程序假设只有套接字和终端才有异步通知能力;如果有多个文件可以异步通知输入的进程,应用程序需要借助poll或者select来确定输入的来源(利用FD_ISSET来判断)。
三,驱动程序角度考虑
那么驱动程序如何来实现异步信号呢?
内核已经提供了很方便的函数给我们使用,为了实现异步信号,驱动程序需要做三件事情:
1)实现fasync方法:该方法也只需要做一步,调用内核提供的fasync_helper函数,如下是scullp设备提供的实现代码:
static int scull_p_fasync(int fd, struct file *filp,int mode)
{
struct scull_pipe *dev = filp->private_data;
return fasync_helper(fd,filp,mode,&dev->async_queue);
}
2)当数据到达时,需要实现异步通知,这时需要调用kill_fasync,当数据可读时,此时需要通知应用程序数据可读,如下是scullp设备提供的代码:
if(dev->async_queue)
kill_fasync(&dev->async_queue,SIGIO,POLL_IN);
如果是为写入提供异步信号,kill_fasync必为模式调用POLL_OUT。
3)在文件关闭时必须调用fasync方法,以便从活动的异步读取进程列表中删除该文件,所有在close方法中有如下调用:
sucll_p_fasync(-1,filp,0);
四,llseeek实现
llseek方法对应lseek和llseek系统调用,该方法通过直接修改filp->f_pos执行定位操作,filp->f_pos记录的文件的读写位置,为了让lseek系统调用正确工作,read/write方法必须通过更新它们收到的偏移量参数来配合。在scull设备中的该方法实现如下:
loff_t scull_llseek(struct file *filp, loff_t off, int whence) { struct scull_dev *dev = filp->private_data; loff_t newpos; switch(whence) { case 0: /* SEEK_SET */ newpos = off; break; case 1: /* SEEK_CUR */ newpos = filp->f_pos + off; break; case 2: /* SEEK_END */ newpos = dev->size + off; break; default: /* can't happen */ return -EINVAL; } if (newpos < 0) return -EINVAL; filp->f_pos = newpos; return newpos; }
相关文章推荐
- Linux设备驱动程序学习(6)-高级字符驱动程序操作[(4)异步通知fasync]
- 【Linux 驱动】第六章 高级字符驱动程序操作 ----阻塞型I/O
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-按键驱动程序之异步通知机制+原子操作+互斥信号量+阻塞与非阻塞+定时器去抖
- 【Linux 驱动】第六章 高级字符驱动程序操作 ----ioctl
- 【Linux 驱动】第六章 高级字符驱动程序操作----poll,select,epoll
- 高级字符驱动程序操作之异步通知IO(实践篇)基于内核2.6.35-30
- Linux设备驱动程序第三版学习(8)- 高级字符驱动程序操作(续3)- 异步通知 .
- 高级字符驱动程序操作之异步通知IO(理论篇)
- linux 驱动——高级字符驱动程序操作
- ldd3学习之十二(3):高级字符驱动程序操作--poll/select、异步通知
- 《Linux Device Drivers》第六章 高级字符驱动程序操作——note
- Linux设备驱动程序第三版学习(8)- 高级字符驱动程序操作(续3)- 异步通知
- 高级字符驱动程序操作之异步通知IO(实践篇)基于内核2.6.35-30
- LDD高级字符驱动程序操作-异步通知
- 高级字符驱动程序操作之异步通知IO(实践篇)
- Linux设备驱动程序学习 高级字符驱动程序操作[阻塞型I/O和非阻塞I/O]【转】
- Linux设备驱动程序第三版学习(6)- 高级字符驱动程序操作(续1) - 进程休眠
- Linux字符设备驱动之异步通知
- linux驱动的异步通知(kill_fasync,fasync)---- 驱动程序向应用程序发送信号
- linux字符设备驱动-异步通知