学习ldd3--异步通知(第六章)
来源:互联网 发布:linux重命名文件的命令 编辑:程序博客网 时间:2024/05/19 03:18
作者:张伟AreS
附加用户空间的asynctest源代码:
/*******************************************************************************/
代码:D:\学习\个人学习笔记及网络经典文章\学习LDD3笔记\ldd3_examples\scull\main.c
D:\学习\个人学习笔记及网络经典文章\学习LDD3笔记\ldd3_examples\scull\pipe.c
代码:D:\学习\个人学习笔记及网络经典文章\学习LDD3笔记\ldd3_examples\scull\main.c
D:\学习\个人学习笔记及网络经典文章\学习LDD3笔记\ldd3_examples\scull\pipe.c
通过使用异步通知机制,应用程序可以在指定的I/O操作可执行时,收到一个信号,而不需要不停的使用轮询来查询设备。
要使用异步通知机制,对于用户空间程序来说,需要执行如下步骤:
首先,指定一个进程作为文件的“属主”,这是通过使用fcntl系统调用执行F_SETOWN命令完成的,该命令会把进程ID号保存在filp->f_owner中.
这一步的目的是让内核知道应该通知哪个进程。
其次,在设备中设置FASYNC标志,这是通过fcntl的F_SETFL命令完成的。
执行完这两个步骤后,当指定的I/O操作可执行时,就会给相应进程发送一个SIGIO信号。
首先,指定一个进程作为文件的“属主”,这是通过使用fcntl系统调用执行F_SETOWN命令完成的,该命令会把进程ID号保存在filp->f_owner中.
这一步的目的是让内核知道应该通知哪个进程。
其次,在设备中设置FASYNC标志,这是通过fcntl的F_SETFL命令完成的。
执行完这两个步骤后,当指定的I/O操作可执行时,就会给相应进程发送一个SIGIO信号。
从内核的角度看,要实现异步通知机制,需要经过如下三个步骤:
首先,F_SETOWN被调用时,对filp->f_owner赋值,此外什么也不做。
其次,执行F_SETFL设置FASYNC时,调用驱动程序的fasync函数。只要filp->f_flags中的FASYNC标志发生了变化,就应该调用这个函数,以便把这个变化通知驱动程序,
使其能做出正确响应。文件打开时,FASYNC标志默认是被清除的。
第三,当指定的I/O操作可执行时,所有注册为异步通知的进程都会被发送一个SIGIO信号。
首先,F_SETOWN被调用时,对filp->f_owner赋值,此外什么也不做。
其次,执行F_SETFL设置FASYNC时,调用驱动程序的fasync函数。只要filp->f_flags中的FASYNC标志发生了变化,就应该调用这个函数,以便把这个变化通知驱动程序,
使其能做出正确响应。文件打开时,FASYNC标志默认是被清除的。
第三,当指定的I/O操作可执行时,所有注册为异步通知的进程都会被发送一个SIGIO信号。
/*************************************/
在用户空间(应用程序)asynctest中,
void sighandler(int signo)
{
if (signo==SIGIO)
gotdata++;//默认为0
return;
}
/*设置sighandler函数为信号处理函数,当有信号从驱动来时,调用此函数(sighandler)处理。*/
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = sighandler; /*指定其为信号来时的处理函数*/
action.sa_flags = 0;
在用户空间(应用程序)asynctest中,
void sighandler(int signo)
{
if (signo==SIGIO)
gotdata++;//默认为0
return;
}
/*设置sighandler函数为信号处理函数,当有信号从驱动来时,调用此函数(sighandler)处理。*/
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = sighandler; /*指定其为信号来时的处理函数*/
action.sa_flags = 0;
sigaction(SIGIO, &action, NULL);
/*在执行F_SETFL启用FASYNC时,调用驱动程序的fasync方法,只要filp->f_flags中的FASYNC标志发生变化时,就会调用该方法
*以便把这个变化通知驱动程序,文件打开时,FASYNC标志被默认清除的
*当数据倒倒时,所有注册为异步通知的进程都会被发送一个SIGIO信号
*/
fcntl(STDIN_FILENO, F_SETOWN, getpid());//进程使用fcntl系统调用执行F_SETOWN命令,属主进程ID号(getpid())被保存在filp->f_owner中。
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | FASYNC);//fcntl通过F_SETFL命令设置FASYNC标志。
/*在执行F_SETFL启用FASYNC时,调用驱动程序的fasync方法,只要filp->f_flags中的FASYNC标志发生变化时,就会调用该方法
*以便把这个变化通知驱动程序,文件打开时,FASYNC标志被默认清除的
*当数据倒倒时,所有注册为异步通知的进程都会被发送一个SIGIO信号
*/
fcntl(STDIN_FILENO, F_SETOWN, getpid());//进程使用fcntl系统调用执行F_SETOWN命令,属主进程ID号(getpid())被保存在filp->f_owner中。
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | FASYNC);//fcntl通过F_SETFL命令设置FASYNC标志。
在驱动中:
/*维护一个动态数据结构struct fasync_struct,以跟踪不同的异步读取进程
*当一个打开的文件的FASYNC标志被修改时,调用fasync_helper以便从相关的进程列表中增加或删除文件。
*除了最后一个参数外,fasync_helper的其它参数与驱动程序的scull_p_fasync函数相同,可以直接传递。
*/
static int scull_p_fasync(int fd, struct file *filp, int mode)//在scullpipe中这样实现fasync方法
{
struct scull_pipe *dev = filp->private_data;
return fasync_helper(fd, filp, mode, &dev->async_queue);//初始化dev->async_queue即struct fasync_struct结构
}
/*当指定的I/O操作可执行时,应使用kill_fasync通知所有的相关进程,
*该函数的第二个参数是要发送的信号(通常是SIGIO),第三个参数是带宽(通常是POLL_IN)。
*由于提供给scullpipe的读取进程的新数据是由某个进程调用write产生的,
*所以kill_fasync函数在scullpipe的write函数中调用
*/
if (dev->async_queue)//此处可去掉,在write函数中之前已判断是否有数据,仅仅去判断struct fasync_struct结构是否已建立
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
//如果是针对写入的异步通知,kill_fasync的第三个参数必须为POLL_OUT。从异步通知的列表中删除该filp
scull_p_fasync(-1,filp,0);
/*即:*/
return fasync_helper(-1, filp, 0, &dev->async_queue);
/*维护一个动态数据结构struct fasync_struct,以跟踪不同的异步读取进程
*当一个打开的文件的FASYNC标志被修改时,调用fasync_helper以便从相关的进程列表中增加或删除文件。
*除了最后一个参数外,fasync_helper的其它参数与驱动程序的scull_p_fasync函数相同,可以直接传递。
*/
static int scull_p_fasync(int fd, struct file *filp, int mode)//在scullpipe中这样实现fasync方法
{
struct scull_pipe *dev = filp->private_data;
return fasync_helper(fd, filp, mode, &dev->async_queue);//初始化dev->async_queue即struct fasync_struct结构
}
/*当指定的I/O操作可执行时,应使用kill_fasync通知所有的相关进程,
*该函数的第二个参数是要发送的信号(通常是SIGIO),第三个参数是带宽(通常是POLL_IN)。
*由于提供给scullpipe的读取进程的新数据是由某个进程调用write产生的,
*所以kill_fasync函数在scullpipe的write函数中调用
*/
if (dev->async_queue)//此处可去掉,在write函数中之前已判断是否有数据,仅仅去判断struct fasync_struct结构是否已建立
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
//如果是针对写入的异步通知,kill_fasync的第三个参数必须为POLL_OUT。从异步通知的列表中删除该filp
scull_p_fasync(-1,filp,0);
/*即:*/
return fasync_helper(-1, filp, 0, &dev->async_queue);
附加用户空间的asynctest源代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
int gotdata=0;
void sighandler(int signo)
{
if (signo==SIGIO)
gotdata++;
return;
}
void sighandler(int signo)
{
if (signo==SIGIO)
gotdata++;
return;
}
char buffer[4096];
int main(int argc, char **argv)
{
int count;
struct sigaction action;
{
int count;
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = sighandler;
action.sa_flags = 0;
action.sa_handler = sighandler;
action.sa_flags = 0;
sigaction(SIGIO, &action, NULL);
fcntl(STDIN_FILENO, F_SETOWN, getpid());
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | FASYNC);
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | FASYNC);
while(1) {
/* this only returns if a signal arrives */
sleep(86400); /* one day */
if (!gotdata)
continue;
count=read(0, buffer, 4096);
/* buggy: if avail data is more than 4kbytes... */
write(1,buffer,count);
gotdata=0;
}
}
/* this only returns if a signal arrives */
sleep(86400); /* one day */
if (!gotdata)
continue;
count=read(0, buffer, 4096);
/* buggy: if avail data is more than 4kbytes... */
write(1,buffer,count);
gotdata=0;
}
}
- 学习ldd3--异步通知(第六章)
- 学习ldd3--ioctl(第六章)
- 学习ldd3--poll(第六章)
- 学习ldd3--llseek(第六章)
- 学习ldd3--简单休眠(第六章)
- 学习ldd3--阻塞型 IO(第六章)
- 学习ldd3--访问控制(第六章)
- LDD3源码分析之异步通知
- LDD3源码分析之异步通知
- LDD3源码分析之异步通知
- LDD3源码分析之异步通知
- 【Linux 驱动】第六章 高级字符驱动程序操作----异步通知
- 学习ldd3--tasklet(第七章)
- 驱动学习 之 异步通知
- ldd3 5 继续学习ldd3
- ldd3 第三章学习感想(1)
- LDD3学习笔记《三》第四章
- LDD3学习笔记《三》第四章
- 10.14js笔记(入门级)
- 学习ldd3--简单休眠(第六章)
- 解决windows8 metro应用不能联网
- 虚假网络 长城宽带
- 从内存理解c语言中变量的存储类型
- 学习ldd3--异步通知(第六章)
- c_str
- 使用 Eclipse Memory Analyzer 检测内存泄漏问题
- 在Windows上安裝Cygwin/GMT系統
- 学习ldd3--阻塞型 IO(第六章)
- 民办院校招生乱象调查
- visitor模式
- 杭州烟花爆炸事故无人重伤-游客衣服包裹头逃生-杭州-烟花爆炸-烧伤
- 学习ldd3--llseek(第六章)