fasync(在内核发生某个事情时向应用发信号, 应用需要把那个设备用fcntl改一下。)
来源:互联网 发布:增值税发票软件app 编辑:程序博客网 时间:2024/06/06 02:25
fasync的解释
fasync (fd,file,on)
当我们呼叫fcntl()系统呼叫,并使用F_SETFL命令来设定档案的参数时,VFS就会呼叫fasync ()这个函式,而当读写档案的动作完成时,行程会收到SIGIO的讯息。
=================================================================================
首先,打开目标设备。
第二,设置好目标设备的SIGIO信号处理程序。
第三,需要通过fcntl系统调用,使当前进程变成文件的主人。(这样才能使文件中的信号
发到当前进程)
第四,通过ioctl系统调用,将目标通道设置成异步操作模式。
在驱动程序的fops中,有一个函数
int (*fasync)(int fd, struct file * file, int on);
在系统调用sys_ioctl的时候,会调用上面的fasync函数。
例如,鼠标器的
int fasync_aux(int fd, struct file * filp, int on)
{
int retval;
retval = fasync_helper(fd, filp, on, &queue->fasync);
if (retval < 0)
return retval;
return 0;
}
这里的queue类似于(struct mydev *)filp->private_data,fasync则是里面的一个fasyn
c队列。
fasync_helper的作用是为当前进程创建一个fasync_struct数据结构,然后挂入目标设备
的fasync队列。
然后,在目标设备的常规驱动处理程序中,向该队列发送信号。
例如,鼠标驱动器的
void handle_mouse_event(unsigned char scancode)(这类似于usb驱动中的int urb,一
个回调函数)
{
......
kill_fasync(&queue->fasync, SIGIO, POLL_IN);
......
}
即向每一个登记的进程发送SIGIO信号。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/walkingman321/archive/2008/03/09/2161304.aspx
=================================================================================
一个简单例子:
#include <linux/module.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/kdev_t.h>#include <linux/cdev.h>#include <linux/kernel.h>#include <linux/string.h>#include <asm/uaccess.h>#include <asm/signal.h>#include <asm-generic/siginfo.h>#define DEVICE_NAME "chardev"static int chardev_open(struct inode *inodp, struct file *filp);static ssize_t chardev_read(struct file *filp, char __user *buff, size_t count, loff_t *f_pos);static ssize_t chardev_write(struct file *filp, const char __user *buff, size_t count, loff_t *f_pos);static int chardev_fasync(int fd, struct file *filp, int mode);static int chardev_release(struct inode *inodp, struct file *filp);static struct file_operations chardev_fops = { .open = chardev_open, .read = chardev_read, .write = chardev_write, .fasync = chardev_fasync, .release = chardev_release,};static struct fasync_struct *async = NULL;static struct semaphore sem;static struct cdev *cdevp;static dev_t devno;static char buffer[8192];static int chardev_open(struct inode *inodp, struct file *filp){ return 0;}static ssize_t chardev_read(struct file *filp, char __user *buff, size_t count, loff_t *f_pos){ if (down_interruptible(&sem)) goto err; count = strlen(buffer); copy_to_user(buff, buffer, count); printk("<0>""read buff is %s/n",buffer); kill_fasync(&async, SIGIO, POLL_IN); up(&sem); dump_stack(); return count;err: return -ERESTARTSYS;}static ssize_t chardev_write(struct file *filp, const char __user *buff, size_t count, loff_t *f_pos){ if (down_interruptible(&sem)) goto err; memset(buffer, '/0', sizeof(buffer)); copy_from_user(buffer, buff, count); printk("<0>""write buff is %s/n",buffer); up(&sem); if (async) // kill_fasync(&async, SIGIO, POLL_IN); dump_stack(); return count;err: return -ERESTARTSYS;}static int chardev_fasync(int fd, struct file *filp, int mode){ //printk("<0>""/nin chardev_fasync/n"); dump_stack(); return fasync_helper(fd, filp, mode, &async);}static int chardev_release(struct inode *inodp, struct file *filp){ //printk("<0>""/nin chardev_release/n"); //printk("<0>""/nin chardev_release twice/n"); dump_stack(); return chardev_fasync(-1, filp, 0);}static int __init chardev_init(void){ int ret; ret = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME); if (ret < 0) goto out; init_MUTEX(&sem); cdevp = cdev_alloc(); if (!cdevp) goto alloc_err; cdev_init(cdevp, &chardev_fops); ret = cdev_add(cdevp, devno, 1); if (!ret) goto out;alloc_err: unregister_chrdev_region(devno, 1);out: return ret;}static void __exit chardev_exit(void){ cdev_del(cdevp); unregister_chrdev_region(devno, 1);}MODULE_LICENSE("GPL");module_init(chardev_init);module_exit(chardev_exit);
=================================================================================
原版例子,上面的改了东西,不对
=================================================================================
#include <linux/module.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/kdev_t.h>#include <linux/cdev.h>#include <linux/kernel.h>#include <linux/string.h>#include <asm/uaccess.h>#define DEVICE_NAME "chardev"static int chardev_open(struct inode *inodp, struct file *filp);static ssize_t chardev_read(struct file *filp, char __user *buff, size_t count, loff_t *f_pos);static ssize_t chardev_write(struct file *filp, const char __user *buff, size_t count, loff_t *f_pos);static int chardev_fasync(int fd, struct file *filp, int mode);static int chardev_release(struct inode *inodp, struct file *filp);static struct file_operations chardev_fops = { .open = chardev_open, .read = chardev_read, .write = chardev_write, .fasync = chardev_fasync, .release = chardev_release,};static struct fasync_struct *async = NULL;static struct semaphore sem;static struct cdev *cdevp;static dev_t devno;static char buffer[8192];static int chardev_open(struct inode *inodp, struct file *filp){ return 0;}static ssize_t chardev_read(struct file *filp, char __user *buff, size_t count, loff_t *f_pos){ if (down_interruptible(&sem)) goto err; count = strlen(buffer); copy_to_user(buff, buffer, count); up(&sem); return count;err: return -ERESTARTSYS;}static ssize_t chardev_write(struct file *filp, const char __user *buff, size_t count, loff_t *f_pos){ if (down_interruptible(&sem)) goto err; memset(buffer, '/0', sizeof(buffer)); copy_from_user(buffer, buff, count); up(&sem); if (async) kill_fasync(&async, SIGIO, POLL_IN); return count;err: return -ERESTARTSYS;}static int chardev_fasync(int fd, struct file *filp, int mode){ return fasync_helper(fd, filp, mode, &async);}static int chardev_release(struct inode *inodp, struct file *filp){ return chardev_fasync(-1, filp, 0);}static int __init chardev_init(void){ int ret; ret = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME); if (ret < 0) goto out; init_MUTEX(&sem); cdevp = cdev_alloc(); if (!cdevp) goto alloc_err; cdev_init(cdevp, &chardev_fops); ret = cdev_add(cdevp, devno, 1); if (!ret) goto out;alloc_err: unregister_chrdev_region(devno, 1);out: return ret;}static void __exit chardev_exit(void){ cdev_del(cdevp); unregister_chrdev_region(devno, 1);}MODULE_LICENSE("GPL");module_init(chardev_init);module_exit(chardev_exit);
=================================================================================
测试程序
=================================================================================
/* * asynctest.c: use async notification to read stdin * * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet * Copyright (C) 2001 O'Reilly & Associates * * The source code in this file can be freely used, adapted, * and redistributed in source or binary form, so long as an * acknowledgment appears in derived source files. The citation * should list that the code comes from the book "Linux Device * Drivers" by Alessandro Rubini and Jonathan Corbet, published * by O'Reilly & Associates. No warranty is attached; * we cannot take responsibility for errors or fitness for use. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <signal.h>#include <fcntl.h>int gotdata=0;static int i = 0;void sighandler(int signo){ if (signo==SIGIO) gotdata++; printf("/nin sighandler %d/n",i); return;}char buffer[4096];int main(int argc, char **argv){ int count; struct sigaction action; FILE *fp; int fd = 0; fd = open("/dev/test",O_RDWR); memset(&action, 0, sizeof(action)); action.sa_handler = sighandler; action.sa_flags = 0; sigaction(SIGIO, &action, NULL); fcntl(fd, F_SETOWN, getpid()); fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC); ++i; while(i != 2) { //printf("/nin while %d/n",++i); /* this only returns if a signal arrives */#if 0 fp = fopen("log2","aw+"); fprintf(fp,"/nin while %d/n",++i); fclose(fp);#endif sleep(2); /* one day */ if (!gotdata) continue; count=read(fd, buffer, 4); printf("/nin while %d/n",++i); /* buggy: if avail data is more than 4kbytes... */ write(fd,buffer,count); //printf("/nin while %d/n",++i); gotdata=0; }}
=================================================================================
总结:
fasync这个东西就是为了使驱动的读写和application的读写分开,使得application可以在驱动读写时去做别的事,通过kill_fasync
(kill_fasync(&async, SIGIO, POLL_IN);)发SIGIO信号给应用,应用通过fcntl把自己这个SIGIO的信号换成自己的响应函数,当驱动发
(kill_fasync(&async, SIGIO, POLL_IN);)给应用时应用就调用了自己的handler去处理。fasync_helper作用就是初始化fasync这个东西,包括分配内存和设置属性。最后记得在驱动的release里把fasync_helper初始化的东西free掉。
=================================================================================
POLL_IN POLL_OUT
=================================================================================
驱动程序向用户程序发信号---------------------------------------------
当设备有IO事件发生,就有机制保证向应用进程发送信号,显然设备驱动程序扮演重要角色,实际终端tty、网络socket等的标准实现已经包括了实时信号驱动的支持,所以,在Linux中它们可以如上直接使用。但有些设备的驱动程序还并没有支持,所以需要定制设备驱动程序。以下两个API应该是可以屏蔽所有相关琐碎操作(类似send_sig())的标准接口:
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()接口的实现(该函数将本进程登记到async_queue上去)。 当一个打开的文件FASYNC标志变化时(调用fcntl()函数,设置FASYNC文件标志时),fasync()接口将被调用。
struct kpp_dev {
struct cdev cdev;
struct fasync_struct *async_queue;
};
static int kpp_fasync(int fd, struct file *filp, int mode)
{
struct kpp_dev *dev = filp->private_data;
return fasync_helper(fd, filp, mode, &dev->async_queue);
}
事件发生的时机,就是中断服务程序或相应的软中断中调用kill_fasync():
if (dev->async_queue)
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
如果是写操作,就是POLL_OUT。注意,无论用户进程设定了什么期望的信号,在这个环节,发送的一般就是SIGIO。注意在设备文件关闭(release方法)时,注意执行fasync(),使得本文件的操作从上述的设备异步事件等待链表中剥离。
static int kpp_release(struct inode *inode, struct file *filp)
{
kpp_fasync(-1, filp, 0);
return 0;
}
- fasync(在内核发生某个事情时向应用发信号, 应用需要把那个设备用fcntl改一下。)
- fasync(在内核发生某个事情时向应用发信号, 应用需要把那个设备用fcntl改一下。)
- fasync(在内核发生某个事情时向应…
- fasync(在内核发生某个事情时向应…
- fcntl()应用
- 应用发布前,需要注意事情
- fcntl函数的应用
- 今天又把昨天那个打星星的程序改了一下!
- 查询某个应用需要那些权限
- 备用数据库的应用
- java在代理服务器软件设中的应用
- 某个课程设计时用到的SQL脚本,贴在这里供自己以后参考一下
- fcntl函数的简单应用
- fcntl函数的简单应用
- fcntl函数的简单应用
- fcntl函数的简单应用
- 为什么需要把应用中出现的文字单独存放在string.xml文件中呢?
- 为什么需要把应用中出现的文字单独存放在string.xml文件中
- f:\arm\program\point\point\point.cpp(24) : error C2512: 'Time' : no appropriate default constructor
- wpf siverlight
- myeclipse10.0优化
- C++强制类型转换
- vim 资源
- fasync(在内核发生某个事情时向应用发信号, 应用需要把那个设备用fcntl改一下。)
- 设定及获取剪切板中的值
- lang lang lang...ago..........
- MySQL Innodb数据库性能实践
- 成功源于专注
- 一些常见小知识
- C# 判断文件是否为空
- 3.天气预报:编写客户端的主类
- 小白积累(QT+OpenGL)