- 论坛徽章:
- 0
|
本帖最后由 alex__nuaa 于 2011-07-19 18:10 编辑
原文链接:http://wahaha02.info/archives/73.html
异步信号
使用信号可以实现设备驱动与用户程序之间的异步通知。为达到此目的:
1. 用户空间需要设置设备文件的拥有者、FASYNC标志及捕获信号;
2. 内核空间需响应对设备文件的拥有者、FASYNC标志的设置,并在资源可获得时释放信号。
1. 设置设备文件的拥有者
用户空间:fcntl(STDIN_FILE, F_SETOWN, getpid());设置设备文件的拥有者为本进程
内核空间:设置设备文件filp的f_owner的pid等相关信息。此部分由内核实现,设备驱动无须处理。
- // in f_setown
- filp->f_owner.pid = pid;
- filp->f_owner.uid = uid;
- filp->f_owner.euid = euid;
复制代码 2. 启用异步通知机制
用户空间:fcntl(STDIN_FILE, F_SETFL, old_flags | FASYNC);
内核空间:设置设备文件支持异步通知模式。
通过调用驱动file_operations函数fasync,设置异步模式。fasync内部会调用fasync_helper,来更新/添加异步通知链表rtc_async_queue。- struct fasync_struct {
- int magic;
- int fa_fd;
- struct fasync_struct *fa_next; /* singly linked list */
- struct file *fa_file;
- };
- static struct fasync_struct *rtc_async_queue;
- // setfl
- if ((arg ^ filp->f_flags) & FASYNC) {
- if (filp->f_op && filp->f_op->fasync) {
- error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
- if (error < 0)
- goto out;
- }
- }
- // rtc_fasync
- static int rtc_fasync(int fd, struct file *file, int on)
- {
- return fasync_helper(fd, file, on, &rtc_async_queue);
- }
- // fasync_helper
- for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
- if (fa->fa_file == filp) {
- if(on) {
- fa->fa_fd = fd;
- kmem_cache_free(fasync_cache, new);
- } else {
- *fp = fa->fa_next;
- kmem_cache_free(fasync_cache, fa);
- result = 1;
- }
- goto out;
- }
- }
- if (on) {
- new->magic = FASYNC_MAGIC;
- new->fa_file = filp;
- new->fa_fd = fd;
- new->fa_next = *fapp;
- *fapp = new;
- result = 1;
- }
复制代码 3. 释放/捕获异步信号
用户空间:signal(SIGIO, input_handler); 设置信号捕获处理函数。
内核空间:释放信号
首先 rtc_probe调用request_irq分配中断资源,设置中断处理函数elapsedtime_interrupt,中断函数内部再调用 kill_fasync,遍历异步通知链表rtc_async_queue,向匹配的f_owner进程发送异步信号(POLL_IN)。- // rtc_probe
- retval = request_irq(irq, elapsedtime_interrupt, SA_INTERRUPT,
- "elapsed_time", NULL);
-
- // elapsedtime_interrupt
- kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
-
- void __kill_fasync(struct fasync_struct *fa, int sig, int band)
- {
- while (fa) {
- struct fown_struct * fown;
- if (fa->magic != FASYNC_MAGIC) {
- printk(KERN_ERR "kill_fasync: bad magic number in "
- "fasync_struct!\n");
- return;
- }
- fown = &fa->fa_file->f_owner;
- /* Don't send SIGURG to processes which have not set a
- queued signum: SIGURG has its own default signalling
- mechanism. */
- if (!(sig == SIGURG && fown->signum == 0))
- send_sigio(fown, fa->fa_fd, band);
- fa = fa->fa_next;
- }
- }
复制代码 异步I/O
AIO通过aiocb来标示。这个结构包含了有关传输的所有信息,包括为数据准备的用户缓冲区。当I/O 完成时,aiocb 结构就被用来惟一标识所完成的 I/O 操作。- struct aiocb {
- int aio_fildes; // File Descriptor
- int aio_lio_opcode; // Valid only for lio_listio (r/w/nop)
- volatile void *aio_buf; // Data Buffer
- size_t aio_nbytes; // Number of Bytes in Data Buffer
- struct sigevent aio_sigevent; // Notification Structure
- /* Internal fields */
- ...
- };
复制代码 异步读写通过aio_read/aio_write,这2个函数在请求进行排队之后会立即返回,所以需要aio_error/aio_return来检查/获取异步请求的状态。
如果不借助异步通知,我们就需要一直检查aio_error来判断AIO的状态,如- ret = aio_read( &my_aiocb );
- if (ret < 0) perror("aio_read");
- while ( aio_error( &my_aiocb ) == EINPROGRESS ) ;
- if ((ret = aio_return( &my_iocb )) > 0) {
- /* got ret bytes on the read */
- } else {
- /* read failed, consult errno */
- }
复制代码 异步通知有2中方法:信号或者回调函数。当AIO完成时,这种机制通过产生一个信号,或者调用用户空间的一个函数来实现异步通知功能。Boost application performance using asynchronous I/O有详细阐述,这里就不再赘言。 |
评分
-
查看全部评分
|