LDD3 P169
驱动程序怎样实现异步信号???从驱动程序的角度考虑
1. F_SETOWN被调用时对filp->f_owner赋值,此外什么也不做
2. 在执行F_SETFL启动FASYNC时,调用驱动程序的fasync方法。只要filp->f_flags中的FASYNC标志发生了变化,就会调用该方法,以便把这个变化通知驱动程序。 文件打开时,FAYSNC标志被默认是清除的。
3. 当数据到达时,所有注册为异步通知的进程都会被发送一个SIGIO信号。
驱动程序中异步通知编程用到:一个数据结构和两个函数,头文件
-
1284 struct fasync_struct {
-
1285 spinlock_t fa_lock;
-
1286 int magic;
-
1287 int fa_fd;
-
1288 struct fasync_struct *fa_next; /* singly linked list */
-
1289 struct file *fa_file;
-
1290 struct rcu_head fa_rcu;
- 1291 };
- fs.h linux-2.6.35
- 1296 extern int fasync_helper(int fd, struct file *filp, int mode, struct fasync_struct **fa);
-
1297/* can be called from interrupts */
- 1298 extern void kill_fasync(struct fasync_struct **fa, int sig, int band);
pp182 在globalmem驱动中增加异步通知
内容修改增加如下:
-
struct globalmem_dev{
-
struct cdev cdev;
-
unsigned char mem[GLOBALMEM_SIZE];////全局内存
-
unsigned int current_len;//fifo有效数据长
-
struct semaphore sem;//并发控制的信号量
-
wait_queue_head_t r_wait; // read //阻塞读用的等待队列头
-
wait_queue_head_t w_wait; // write
-
struct fasync_struct *async_queue;////异步结构体指针,用于读
- };
-
static int globalmem_fasync(int fd,struct file *filp,int mode)
-
{
-
struct globalmem_dev *dev=filp->private_data;
-
return fasync_helper(fd,filp,mode,&dev->async_queue);
- }
- write函数中
-
////产生异步读信号
-
if(dev->async_queue)
- kill_fasync(&dev->async_queue,SIGIO,POLL_IN);
在设备资源可以获得时,调用kill_fasync()释放SIGIO,可读时第三个参数设置为POLL_IN,可写时第三个参数设置为POLL_OUT
在ldd3 p171:当数据到达时,必须执行上述语句来通知异步读取进程。由于供给glebalmem的读取进程的新数据是由某个进程调用write产生的,所以这条语句在write方法中。
当设备可写时,在read方法中实现,这时,kill_fasync必须是 POLL_OUT
-
int globalmem_release(struct inode *inode,struct file *filp)
-
{
-
////将文件从异步列表中删除
-
globalmem_fasync(-1,filp,0);
-
return 0;
- }
-
void input_handler(int signum)
-
{
-
printf("receive a signal from globalmem fifo,signalnum:%d\n",signum);
-
}
-
-
int main(int argc, char **argv)
-
{
-
int fd;
-
int oflags;
-
-
fd = open("/dev/globalmem",O_RDWR,S_IRUSR | S_IWUSR);
-
if(fd != -1)
-
{
-
////
-
signal(SIGIO,input_handler);
-
fcntl(fd,F_SETOWN,getpid());
-
oflags = fcntl(fd,F_GETFL);
-
fcntl(fd,F_SETFL,oflags | FASYNC);
-
while(1)
-
sleep(1);
-
}
-
else
-
{
-
printf("device open faiure\n");
-
exit(EXIT_FAILURE);
-
}
- }
使用:
-
sudo insmod ./globalmem.ko
- sudo mknod /dev/globalmem c 240 0
- root@ywx:/globalmem_fifo_async/application# ls
- app app.c app.o Makefile
- root@ywx:/globalmem_fifo_async/application# ./app &
- [1] 6800
-
root@ywx:/globalmem_fifo_async/application# echo 1 > /dev/globalmem
-
receive a signal from globalmem fifo,signalnum:29
- 当有数据输入的时候,应用程序会返回信息,异步通知 实现了
-
root@ywx:/globalmem_fifo_async/application# echo "i love linux" > /dev/globalmem
-
receive a signal from globalmem fifo,signalnum:29
-
root@ywx:/globalmem_fifo_async/application# ps -A | grep app 查找我们运行的应用程序
-
1705 ? 00:00:00 bluetooth-apple
-
1708 ? 00:00:00 nm-applet
-
1776 ? 00:00:01 wnck-applet
-
1784 ? 00:00:00 trashapplet
-
1824 ? 00:00:00 indicator-apple
-
1828 ? 00:00:04 clock-applet
-
1829 ? 00:00:00 indicator-apple
-
1881 ? 00:00:00 indicator-appli
-
1896 ? 00:00:00 applet.py
- 6800 pts/2 00:00:00 app 这是我们执行的应用程序
参考资料:
1.小白:chinaunix linux设备驱动归纳总结(三):7.异步通知fasync
2.
总结:
信号异步通知 不会引起进程阻塞,而且进程也不知道什么时候信号会发出。
使用信号可以实现设备驱动与用户程序之间的异步通知,总体而言,设备驱动和用户空间要分别完成3项对应的工作,用户空间设置文件的拥有者、FASYNC标志及捕获信号,内核空间要对文件的拥有者、FASYNC标志的设置并在资源科获得时释放信号。