linux驱动程序中的异步编程
A
前面介绍的等待队列和轮询编程提供了较好的解决设备访问的机制,但是这些机制都
是由应用程序发起的,都需要应用程序主动访问设备。更完美的方式是由驱动程序主
动通知应用程序,也就是说,当驱动程序满足某些条件后,会主动通知应用程序处理
,这些处理方式有些像面向对象编程的事件,而在linux内核使用的事件是接下来要介
绍的信号。
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<fcntl.h>
#include<signal.h>
#include<unistd.h>
#define MAX_LEN 100
void input_handler(int num) //捕获处理函数
{
char data[MAX_LEN];
int len;
len=read(STDIN_FILENO,&data,MAX_LEN);
data[len]=0;
printf("input available:%s\n",data);
}
main()
{
int oflags;
signal(SIGIO,input_handler); //捕获SIGIO信号
//通过F_SETOWN将标准输入设备文件(驱动)STDIN_FILENO--的拥有者设置为
//当前进程,这样从设备驱动STDIN_FILENO发出的信号才能被当前进程所接到。
fcntl(STDIN_FILENO,F_SETOWN,getpid());
oflags=fcntl(STDIN_FILENO,F_GETFL);
// 通过F_SETFL使设备文件支持FASYNC,也就是异步通知模式。
fcntl(STDIN_FILENO,F_SETFL,oflags|FASYNC);
while(1);
}
B
设备驱动中异步通知编程比较简单,主要用到一项数据结构和两个函数。
数据结构是 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);
和其他的设备驱动一样,将 fasync_struct 结构体指针放在设备结构体中仍然是最
佳选择,代码清单给出了支持异步通知的设备结构体模板。
struct xxx_dev
{
struct cdev cdev; /*cdev 结构体*/
...
struct fasync_struct *async_queue; /* 异步结构体指针 */
};
在设备驱动的 fasync() 函数中,只需要简单地将该函数的 3 个参数以及
fasync_struct 结构体指针的指针作为第 4 个参数传入 fasync_helper()函数即
可。代码清单给出了支持异步通知的设备驱动程序 fasync()函数的模板。
//处理应用程序的F_SETFL命令的fasync函数
static int xxx_fasync(int fd, struct file *filp, int mode){
struct xxx_dev *dev = filp->private_data;
return fasync_helper(fd, filp, mode, &dev->async_queue);
}
static struct file_operations dev_fops=
{
.owner=...
.read=....
.write=...
.fasync=xxx_fasync;
}
在设备资源可以获得时,应该调用 kill_fasync()释放 SIGIO 信号,可读时第 3
个参数设置为 POLL_IN,可写时第 3 个参数设置为 POLL_OUT。下面代码为释放信号
的范例。
static ssize_t xxx_write(struct file *filp, const char _ _user *buf, size_t count,loff_t *f_pos}
{
struct xxx_dev *dev = filp->private_data;
...
if (dev->async_queue)
kill_fasync(&dev->async_queue, SIGIO, POLL_IN); /* 产生异步读信号 */
...
}
最后,在文件关闭时,即在设备驱动的 release()函数中,应调用设备驱动的
fasync()函数将文件从异步通知的列表中删除。下面代码清单给出了支持异步通知的
设备驱动release()函数的模板。
static int xxx_release(struct inode *inode, struct file *filp)
{
struct xxx_dev *dev = filp->private_data;
/* 将文件从异步通知列表中删除 */
xxx_fasync(-1, filp, 0);
...
return 0;
}
应用程序:
打开两个终端,一个运行应用程序,另外一个执行 echo "hello" >/dev/设备名 ,
执行完这条指令后,驱动调用write函数,驱动程序中的write函数中会调用
kill_fasync(&dev->async_queue, SIGIO, POLL_IN); /* 产生异步读信号 */ ,
这样应用程序马上捕捉到SIGIO,此时应用程序进入处理接受信号函数。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。