精华内容
下载资源
问答
  • 异步通知意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上“中断”的概念,比较准确的称谓是“信号驱动的异步I/O”。信号是在软件层次上对中断机制的一...

    异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上“中断”的概念,比较准确的称谓是“信号驱动的异步I/O”。信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。
    阻塞I/O意味着一直等待设备可访问后再访问,非阻塞I/O中使用poll()意味着查询设备是否可访问,而异步通知则意味着设备通知用户自身可访问,之后用户再进行I/O处理。由此可见,这几种I/O方式可以相互补充。Linux信号及其定义
    一个信号被捕获的意思是当一个信号到达时有相应的代码处理它。如果一个信号没有被这个进程所捕获,内核将采用默认行为处理。
    信号的接收
    在用户程序中,为了捕获信号,可以使用signal()函数来设置对应的信号处理函数:
    void (*signal (int signum, void (*handler))(int ))) (int);
    可以分解为:
    typedef void (*signadler_t) (int);
    sighandler_t signal(int signum, sighandler_t handler);
    第一个参数signum指定信号的值,第二个函数指针参数指定针对前面信号值的处理函数,若为SIG_IGN,表示忽略该信号;若为SIG_DFL,表示采用系统默认的方式处理信号;若为用户自定义的函数,则信号被捕获后,该函数将被执行。
    如果signal()调用成功,它返回最后一次为信号signum绑定的处理函数的handler值,失败则返回SIG_ERR。

    在进程执行时,按下“Ctrl+C”将向其发出SIGINT信号,正在运行kill的进程将向其发出SIGTERM信
    号,以下代码中的进程可捕获这两个信号并输出信号值。
    void sigterm_handler(int signo)
    {
    printf(“Have caught sig N.O. %d\n”, signo);
    exit(0);

    }
    int main(void)
    {
    signal(SIGINT, sigterm_handler);
    signal(SIGTERM, sigterm_handler);
    while(1);
    return 0;
    }

    除了signal()函数外,sigaction()函数可用于改变进程接收到特定信号后的行为,它的原型为:
    int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
    该函数的第一个参数为信号的值,可以是除SIGKILL及SIGSTOP外的任何一个特定有效的信号。第二个参数是指向结构体sigaction的一个实例的指针,在结构体sigaction的实例中,指定了对特定信号的处理函数,若为空,则进程会以缺省方式对信号处理;第三个参数oldact指向的对象用来保存原来对相应信号的处理函数,可指定oldact为NULL。如果把第二、第三个参数都设为NULL,那么该函数可用于检查信号的有效性.

    先来看一个使用信号实现异步通知的例子,它通过signal(SIGIO,input_handler)对标准输入文件描述符STDIN_FILENO启动信号机制。用户输入后,应用程序将接收到SIGIO信号,其处理函数input_handler()将被调用.

    include

    include

    include

    include

    include

    include

    define MAX_LEX 100

    void input_handler(int num)
    {
    char data[MAX_LEN];
    int len;
    // 读取并输出STDIN_FILENO上的输入
    len = read(STDIN_FILENO, &data, MAX_LEN);
    data[len] = 0;
    printf(“input available: %d\n”, data);
    }

    void main()
    {
    int oflags;
    // 启动信号驱动机制
    signal(SIGIO, input_handler); // 将SIGIO信号同input_handler函数关联起来,一旦产生SIGIO信号,就会执行input_handler函数
    // STDIN_FILENO是打开的设备文件描述符,F_SETOWN用来决定操作是干什么的,getpid()是个系统调用,功能是返回当前进程
    //的进程号,整个函数的功能是STDIN_FILENO设置这个设备文件拥有者为当前进程
    fcntl(STDIN_FILENO, F_SETOWN, getpid());
    oflags = fcntl(STDIN_FILENO, F_SETFL, ofags | FASYNC); // 得到打开文件描述符的状态
    // 设置文件描述符的状态为oflags | FASYNC属性,一旦文件描述符被设置程具有FASYNC属性的状态,也就是将设备文件切换到
    // 异步操作模式,这时系统会自动调用驱动程序的fasync方法。
    fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC);
    // 最后进入一个死循环,仅为保持进程不终止,如果程序中没有这个死循环会立即执行完毕
    while(1);
    }

    ssize_t (read)(struct file *filp, char __user *buffer, size_t size, loff_t p);
    filp:为进行读取信息的目标文件;
    buffer:为放置信息的缓冲区(即用户空间地址);
    size:为要读取的信息长度;
    p:为要读取的位置相对文件开头的偏移,在读取信息后,这个指针一般都会移动,移动的值为要读取的信息的长度;

    ssize_t (write) (struct file *filp, char __user buffer, size_t count , loff_t *ppos);
    filp :为目标文件结构体指针;
    buffer :为要写入文件的信息缓冲区;
    count :为要写入信息的长度;
    ppos :为当前的偏移位置,这个值通常是用来判断写文件是否越界

    fcntl()

    include

    include

    include

    include

    include

    include

    展开全文
  • 异步通知意思就是,一旦设备就绪,则主动通知应用程序,这样应用程序根本不需要查询设备状态,非常类似于硬件上"中断的概念" 准确一点就叫:信号驱动(SIGIO)的异步I/O 实现异步通知,内核需要知道几个东西:哪个...

    异步通知:意思就是,一旦设备就绪,则主动通知应用程序,这样应用程序根本不需要查询设备状态,非常类似于硬件上"中断的概念"

    准确一点就叫:信号驱动(SIGIO)的异步I/O

    实现异步通知,内核需要知道几个东西:哪个文件(filp),什么信号(SIGIIO),发给哪个进程(pid),收到信号后做什么(sig_handler)。这些都由上述前两个步骤完成了,而这前两个步骤内核帮忙实现了,所以,我们只需要实现第三个步骤的一个简单的传参。

    设置异步通知的步骤(针对应用层来说的):
    1.首先指定一个进程作为文件的属主。通过使用fcntl系统调用执行F_SETOWN命令时,属主进程的ID号就会保存在filp->f_owner中,目的是为了让内核知道应该通知哪个进程。
    2.在设备中设置FASYNC标志。通过fcntl调用的F_SETFL来完成。
    设置晚以上两步后,输入文件就可以在新数据到达时请求发送一个SIGIO信号,该信号被发送到存放在filp->f_owner中的进程。

    通过signal(SIGIO,input_handler)对STDIN_FILENO启动信号机制,

    /*
    异步通知3个步骤:
    1,signal(SIGIO, input_handler); 
    调用signal函数,让指定的信号SIGIO与处理函数input_handler对应;
    2,fcntl(STDIN_FILENO, F_SETOWN, getpid()); 
    指定一个进程作为文件的属主(filp->owner),这样内核才知道信号要发给哪个进程
    3,   oflags = fcntl(STDIN_FILENO, F_GETFL); //F_GETFL读取文件状态标识
        fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC); //F_SETFL:设置文件状态标识
    在设备文件中添加FASYNC标识,驱动中就会调用将要实现的input_handler函数
    这3个步骤执行后,一旦有信号产生,相应的进程就会收到


    */


    #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; 
     
        //读取并输出 STDIN_FILENO 上的输入 
        len = read(STDIN_FILENO, &data, MAX_LEN); 
        data[len] = 0; 
        printf("input available:%s\n", data); 

     
    main() 

        int oflags; 
     //函数原型:sig_t signal(int signum,sig_t handler); 
     //signum:指明要处理的信号类型
     //handler:描述了与信号关联的动作,可以取以下3种值:
     //1,一个返回值为正数的函数地址,此函数必须在signal被调用前申明,handler中为这个函数的名字
     //当接收到一个类型为sig的信号时,就执行handler所指定的函数,这个函数的定义形式应该为:
     //int func(int sig),sig是传递给它的唯一参数,执行了signal调用之后,进程只要收到类型为sig的信号
     //不管其正在执行程序的哪一部分,就立即执行func()函数,当func()函数执行结束后,控制权返回进程被中断的那一点继续执行
     //2,SIGIGN:表示忽略该信号,执行了相应的signal()调用后,进程忽略类型为sig的信号
     //3,SIGDFL 这个符号表示恢复系统对信号的默认处理
      //函数说明:signal()会依参数signum指定的信号编号来设置该信号的处理函数,当指定的信号到达时就会跳转到函数handler指定的函数执行
      //当一个信号的信号处理函数执行时,如果进程又接收到了该信号,该信号会自动被储存而不会中断信号处理函数的执行
      //直到信号处理函数执行完毕再重新调用相应的处理函数,但是如果在信号处理函数执行时进程收到了其它类型的信号,该函数的执行就会被中断
      //返回值;返回先前的信号处理函数指针,如果有错误则返回SIG_ERR(-1).  
        //启动信号驱动机制 
        signal(SIGIO, input_handler); 
        
        //fcntl:根据文件描述词来操作文件的特性
        //通过这个函数改变一个已打开的文件的属性,可以重新设置读,写,追加,非阻塞等标识


        /*
        用法:   
    int fcntl(int fd, int cmd); 
    int fcntl(int fd, int cmd, long arg); 
    int fcntl(int fd, int cmd, struct flock *lock); 
    参数:
    fd:文件描述词。 
    cmd:操作命令。 
    arg:供命令使用的参数。 
    lock:同上。


        */
        //getpid()用于取得目前进程的进程ID
        //STDIN_FILENO:系统级API接口库
        //F_SETOWN:设置将要在文件描述词fd上接收SIGIO或SIGURG事件信号的进程或进程组标识
        fcntl(STDIN_FILENO, F_SETOWN, getpid()); 
        oflags = fcntl(STDIN_FILENO, F_GETFL); //F_GETFL读取文件状态标识
        fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC); //F_SETFL:设置文件状态标识
      //其中O_RDONLY, O_WRONLY, O_RDWR, O_CREAT,  O_EXCL, O_NOCTTY 和 O_TRUNC不受影响,可以更改的标志有 O_APPEND,O_ASYNC, O_DIRECT, O_NOATIME 和 O_NONBLOCK。 
        //最后进入一个死循环,程序什么都不干了,只有信号能激发 input_handler 的运行 
        //如果程序中没有这个死循环,会立即执行完毕 
        while (1); 
    }

    展开全文
  •  异步通知意思是: 一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上“中断”的概念,比较准确的称谓是“信号驱动的异步I/O”。信号是在软件层次上对中断机制的...

    1. 基本概念

        异步通知的意思是: 一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上“中断”的概念,比较准确的称谓是“信号驱动的异步I/O”。信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。
        阻塞I/O意味着一直等待设备可访问后再访问,非阻塞I/O中使用poll()意味着查询设备是否可访问,而异步通知则意味着设备通知用户自身可访问,之后用户再进行I/O处理。由此可见,这几种I/O方式可以相互补充。

    2. 使用异步通知

        使用信号进行进程间通信(IPC)是UNIX中的一种传统机制,Linux也支持这种机制。在Linux中,异步通知使用信号来实现, Linux中可用的信号及其定义如下: 

        除了SIGSTOPSIGKILL两个信号外,进程能够忽略或捕获其他的全部信号。一个信号被捕获的意思是当一个信号到达时有相应的代码处理它,如果一个信号没有被这个进程所捕获,内核将采用默认行为处理。

    2.1 信号的接收

        在用户程序中, 为了捕获信号, 可以使用signal() 函数来设置对应信号的处理函数:

    void (*signal(int signum, void (*handler))(int)))(int);

        第一个参数指定信号的值,第二个参数指定针对前面信号值的处理函数,若为SIG_IGN,表示忽略该信号;若为SIG_DFL,表示采用系统默认方式处理信号;若为用户自定义的函数,则信号被捕获到后,该函数将被执行。如果signal() 调用成功,它返回最后一次为信号signum绑定的处理函数的handler值,失败则返回SIG_ERR。
        信号接收部分完全在应用程序中,完整应用程序fasync_text.c代码如下:

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <poll.h>
    #include <signal.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <fcntl.h>
    
    /* fasync_text
      */
    void my_signal_fun(int signum)
    {
    	printf("received signal SIGIO!\n");
    }
    
    int main(int argc, char **argv)
    {
    	int Oflags;
    	int fd;
    	
    	signal(SIGIO, my_signal_fun);
    	
    	fd = open("/dev/test", O_RDWR);
    	if (fd < 0)
    	{
    		printf("can't open /dev/test !\n");
    	}
    
    	fcntl(fd, F_SETOWN, getpid());    //定义该驱动要发送信号给哪个进程(PID)
    	Oflags = fcntl(fd, F_GETFL); 
    	fcntl(fd, F_SETFL, Oflags | FASYNC);
    
    	while (1)
    	{
    		sleep(1000);
    	}
    	return 0;
    }
    
    

        fcntl(fd, F_SETOWN, getpid());
        Oflags = fcntl(fd, F_GETFL);
        fcntl(fd, F_SETFL, Oflags | FASYNC);

        这3行代码的作用是为了能在用户空间中处理一个设备释放的信号, 分别的作用是:
        (1) 通过F_SETOWN IO控制命令设置设备文件的拥有者为本进程, 这样从设备驱动发出的信号才能被本进程接收到。
        (2) 通过F_SETFL IO控制命令设置设备文件以支持FASYNC, 即异步通知模式。
        (3) 通过signal( ) 函数连接信号和信号处理函数。

        这样,当应用程序接收到SIGIO这个信号时,就会调用my_signal_fun()函数了,就可以实现设备驱动通知应用程序去执行某些工作了。

    2.2 信号的释放

        应用程序端负责捕获信号,则设备驱动负责释放信号,需要在设备驱动程序中增加信号释放的相关代码。
        为了使设备支持异步通知机制, 驱动程序中涉及3项工作:
        (1) 支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID。不过此项工作已由内核完成,设备驱动无须处理。
        (2) 支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行。因此,驱动中应该实现fasync() 函数。
        (3) 在设备资源可获得时,调用kill_fasync()函数激发相应的信号。

        上述的3项工作和应用程序中的3项是对应的,他们之间的关系,如下图:


    完整驱动程序fasync_drv.c代码如下:

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/init.h>
    #include <linux/interrupt.h>
    #include <linux/sched.h>
    #include <linux/init.h>
    #include <linux/timer.h>
    #include <linux/cdev.h>
    
    
    int major;
    static struct cdev test_cdev;
    static struct class *test_class;
     
    struct timer_list timer;    //定义一个定时器
    static struct fasync_struct *test_async;
    
    /*每隔5秒发送一次SIGIO信号*/
    void test_function(unsigned long arg)
    {
    	mod_timer(&timer, jiffies + (5*HZ));	//重新设置定时器,每隔5秒执行一次
    
    	printk("send signal SIGIO to user!\n");
    	kill_fasync(&test_async, SIGIO, POLL_IN);
    }
    
    static int test_open(struct inode *inode, struct file *file)
    {
    	init_timer(&timer);     		//初始化定时器
        timer.expires = jiffies+(5*HZ); //设定超时时间,5秒
        timer.data = 5;    				//传递给定时器超时函数的值
        timer.function = test_function; //设置定时器超时函数
        add_timer(&timer); 				//添加定时器,定时器开始生效
    
    	return 0;
    }
    
    static int test_fasync(int fd, struct file * file, int on)
    {
    	printk("driver: test_fasync\n");
    	return fasync_helper(fd, file, on, &test_async);
    }
    
    int test_close(struct inode *inode, struct file *file)
    {	
    	del_timer(&timer);		 //删除定时器
    	test_fasync(-1, file, 0);	 //将文件从异步通知列表中删除
    	return 0;
    }
    
    static struct file_operations test_fops = {
        .owner   =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
        .open    =  test_open,     
        .fasync  =	test_fasync,
        .release =  test_close,
    };
    
    static int test_init(void)
    {
    	int result;
    	dev_t devid = MKDEV(major, 0);	//从主设备号major,次设备号0得到dev_t类型
    	if (major) 
    	{
    		result=register_chrdev_region(devid, 1, "test");	//注册字符设备
    	} 
    	else 
    	{
    		result=alloc_chrdev_region(&devid, 0, 1, "test");	//注册字符设备
    		major = MAJOR(devid);		//从dev_t类型得到主设备
    	}
    	if(result<0)
    		return result;
    	
    	cdev_init(&test_cdev, &test_fops);
    	cdev_add(&test_cdev, devid, 1);
    	test_class = class_create(THIS_MODULE, "test_drv");
    	class_device_create(test_class, NULL, MKDEV(major, 0), NULL, "test"); /* /dev/buttons */
    
    	return 0;
    }
    
    static void test_exit(void)
    {
    	class_device_destroy(test_class, MKDEV(major, 0));
    	class_destroy(test_class);
    	cdev_del(&test_cdev);
    	unregister_chrdev_region(MKDEV(major, 0), 1);
    }
    
    module_init(test_init);
    module_exit(test_exit);
    MODULE_AUTHOR("LVZHENHAI");
    MODULE_LICENSE("GPL");
    
    

    Makefile如下:

    KERN_DIR = /work/system/linux-2.6.22.6    //内核目录
     
    all:
    	make -C $(KERN_DIR) M=`pwd` modules 
     
    clean:
    	make -C $(KERN_DIR) M=`pwd` modules clean
    	rm -rf modules.order
     
    obj-m	+= fasync_drv.o

    3. 测试

    内核:linux-2.6.22.6
    编译器:arm-linux-gcc-3.4.5
    环境:ubuntu9.10

    fasync_drv.c、fasync_test.c、Makefile三个文件放入网络文件系统内,在ubuntu该目录下执行:
        make
        arm-linux-gcc -o fasync_test fasync_test.c

    在挂载了网络文件系统的开发板上进入相同目录,执行“ls”查看:

    装载驱动:
        insmod fasync_drv.ko
    运行测试程序:
        ./fasync_test
    结果如下:

    每隔5秒都会打印:
        send signal SIGIO to user!
        received signal SIGIO!

    4. 程序说明

    应用程序open打开驱动,驱动里就会创建一个5秒循环启动的定时器,然后应用程序设置好异步通知模式后,直接进入while死循环里。驱动程序每5秒启动定时器函数发送SIGIO信号,打印send signal SIGIO to user!,应用程序就会接受到信号并打印received signal SIGIO!。

     

    展开全文
  • 异步通知意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上“中断”的概念,比较准确的称谓是“信号驱动的异步I/O”.信号是在软件层次上对中断机制的一种模拟...

    前言

    异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上“中断”的概念,比较准确的称谓是“信号驱动的异步I/O”.信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。
    在这里插入图片描述

    应用层

    实现异步通知机制,用户程序涉及2项工作,首先,得指定一个进程作为文件的“属主(owner)”.当应用程序使用fcntl系统调用执行F_SETOWN命令时,属主进程的进程ID号就被保存在filp->f_owner中.这一步是必需的,目的是告诉内核将信号发给谁,也就是发给哪个进程.然后为了真正启动异步通知机制,用户程序还必须在设备中设置FASYNC标志,这通过fcntl的F_SETFL命令完成的,文件打开时,FASYNC标志被默认为是清除的.,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行。.执行完这两个步骤之后,内核就可以在新数据到达时通过调用kill_fasync()函数请求发送一个SIGIO信号给应用层,该信号被发送到存放在filp->f_owner中的进程(如果是负值就是进程组)
    在这里插入图片描述

    内核层

    根据内核源码来看看调用过程,应用层调用fcntl(),会进行系统调用sys_fcntl(),接着调用do_fcntl(),再根据cmd调用相应的操作函数
    sys_fcntl

    asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
    {	
    	struct file *filp;
    	long err = -EBADF;
    
    	filp = fget(fd);//通过文件描述符获得相应的文件指针
    	if (!filp)
    		goto out;
    
    	err = security_file_fcntl(filp, cmd, arg);//调用do_fcntl函数
    	if (err) {
    		fput(filp);
    		return err;
    	}
    
    	err = do_fcntl(fd, cmd, arg, filp);
    
     	fput(filp);
    out:
    	return err;
    }
    

    do_fcntl

    static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
    		struct file *filp)
    {
    	long err = -EINVAL;
        ......
    	case F_GETFL: //返回文件标志
    		err = filp->f_flags;
    		break;
    	case F_SETFL:
    		err = setfl(fd, filp, arg);//转调用setfl函数
    		break;
    	case F_SETOWN:
    		err = f_setown(filp, arg, 1);//转调用f_setown函数
    		break;
    	.......
    	default:
    		break;
    	}
    	return err;
    }
    

    setfl函数的内部实现

    static int setfl(int fd, struct file * filp, unsigned long arg)
    {
        struct inode * inode = filp->f_dentry->d_inode;
        int error = 0;
        ……
        lock_kernel();
        //下面这个判断语句有点意思,是一个边缘触发
        //FASYNC标志从0变为1的时候为真
        if ((arg ^ filp->f_flags) & FASYNC) {//FASYNC标志发生了变化
            if (filp->f_op && filp->f_op->fasync) {
                error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);//每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行。
                if (error < 0)
                    goto out;
            }
        }
    
        filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
     out:
        unlock_kernel();
        return error;
    }t
    

    f_setown函数的内部实现

    int f_setown(struct file *filp, unsigned long arg, int force)
    {
        int err;
    
        err = security_file_set_fowner(filp);
        if (err)
            return err;
    
        f_modown(filp, arg, current->uid, current->euid, force);//调用f_modown函数
        return 0;
    }
    
    
    static void f_modown(struct file *filp, unsigned long pid,
                         uid_t uid, uid_t euid, int force)
    {
        write_lock_irq(&filp->f_owner.lock);
        //设置对应的pid,uid,euid
        if (force || !filp->f_owner.pid) {
            filp->f_owner.pid = pid;
            filp->f_owner.uid = uid;
            filp->f_owner.euid = euid;
        }
        write_unlock_irq(&filp->f_owner.lock);
    }
    

    相关的数据结构和函数

    struct fasync_struct {
        int magic;
        int fa_fd;//文件描述符
        struct  fasync_struct   *fa_next; /* singly linked list *///异步通知队列
        struct  file        *fa_file;//文件指针
    };
    

    处理FASYNC标志变更的函数

    int fasync_helper(int fd, struct file *filp, int mode, struct fasync_struct **fa);
    
    int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
    {
        struct fasync_struct *fa, **fp;
        struct fasync_struct *new = NULL;
        int result = 0;
    
        if (on) {
            new = kmem_cache_alloc(fasync_cache, SLAB_KERNEL);//创建对象,slab分配器
            if (!new)
                return -ENOMEM;
        }
        write_lock_irq(&fasync_lock);
        //遍历整个异步通知队列,看是否存在对应的文件指针
        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;
        }
    out:
        write_unlock_irq(&fasync_lock);
        return result;
    }
    

    释放信号用的函数

    void kill_fasync(struct fasync_struct **fa, int sig, int band);
    
    void kill_fasync(struct fasync_struct **fp, int sig, int band)
    {
        /* First a quick test without locking: usually
         * the list is empty.
         */
        if (*fp) {
            read_lock(&fasync_lock);
            /* reread *fp after obtaining the lock */
            __kill_fasync(*fp, sig, band);//调用
            read_unlock(&fasync_lock);
        }
    }
    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;//这就是应用层使用F_SETOWN的意义,让其通过异步对象的文件指针知道其主进程
            if (!(sig == SIGURG && fown->signum == 0))
                send_sigio(fown, fa->fa_fd, band);//向主进程发送信号,也就是向我们的执行了fcntl(fd,F_SETOWN,getpid())命令的应用程序发送信号
            fa = fa->fa_next;
        }
    }
    

    当一个打开的文件的FASYNC标志被修改时,调用fasync_helper函数以便从相关的进程表中添加或删除文件.当数据到达时,可使用kill_fasync函数通知所有的相关进程。

    展开全文
  • 异步通知意思是: 一旦设备就绪, 则驱动主动通知应用程序, 这样应用程序根本就不需要查询设备状态, 这一点非常类似于硬件上“中断”的概念, 比较准确的称谓是“信号驱动的异步I/O”。 信号是在软件层次上对...
  • 异步通知意思就是,一旦设备就绪,则主动通知应用程序,应用程序根本就不需要查询设备状态,类似于中断的概念,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何...
  • 什么异步通知:很简单,一旦设备准备好,就主动通知应用程序,这种情况下应用程序就不需要查询设备状态, 特像硬件上常提的“中断的概念”。 比较准确的说法其实应该叫做“信号驱动的异步I/O”,信号是在软件层次上...
  • 首先,本文讨论的单线程的问题,多CPU多线程的情况不在考虑范围,不过思想都是...异步,只是简单地向操作系统注册完一个函数,操作系统在IO操作完成后,用信号通知该进程。例如[2], 第一行,signal不必等到 on_...
  • 异步意思就是非顺序执行的。至于执行的顺序是什么,这是不确定的。而某个任务要执行到什么时间结束,这要看分给这个任务的CPU时间。时间到了就结束(分时系统,大部分情况都是这样)。 为什么需要异...
  • Linux异步机制

    千次阅读 2016-05-10 18:24:09
    什么异步通知:很简单,一旦设备准备好,就主动通知应用程序,这种情况下应用程序就不需要查询设备状态, 特像硬件上常提的“中断的概念”。 比较准确的说法其实应该叫做“信号驱动的异步I/O”,信号是在软件层次上...
  • 121-同步 IO 与异步 IO

    千次阅读 2017-03-28 14:48:40
    1. 引言至今为止,我们学习到的所有 IO 都是同步 IO。其主要特征是使用 read 或 ...我有点不太理解中文版本的 apue 把 select 和 poll 说成可以实现异步形式的通知什么意思。参考图 1. 图 1 apue 中文版本有关异
  • 异步异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,只要自己完成了整个任务就算完成了阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他...
  • Android bindService是一个异步过程

    千次阅读 2018-01-16 20:49:13
    Android中bindService是一个异步的过程,什么意思呢?使用bindService无非是想获得一个Binder服务的Proxy,但这个代理获取到的时机并非由bindService发起端控制,而是由Service端来控制,也就是说bindService之后,...
  • 非阻塞式通常是对于I/O操作而言的,意思就是当你请求一个系统调用的时候,不管收到什么结果函数都会立即返回,而不让线程进入休眠状态以等待I/O操作的完成。相反阻塞式I/O方式在请求一个磁盘文件时会进入线程休眠...
  • Android中bindService是一个异步的过程,什么意思呢?使用bindService无非是想获得一个Binder服务的Proxy,但这个代理获取到的时机并非由bindService发起端控制,而是由Service端来控制,也就是说bindService之后,...
  • Android中bindService是一个异步的过程,什么意思呢?使用bindService无非是想获得一个Binder服务的Proxy,但这个代理获取到的时机并非由bindService发起端控制,而是由Service端来控制,也就是说bindService之后,...
  • 本文已收录GitHub,更有互联网大厂面试真题,面试攻略,高效学习资料等 ...通过这两种系统的名字,估计你也能大概猜出来 IO 密集型系统是什么意思。 IO 密集型系统大部分时间都在执行 IO 操作,这个 IO.
  • 异步与同步模型最大的区别是,同步模型会阻塞线程等待资源,而异步模型不会阻塞线程,它是等资源准备好后,...通过这两种系统的名字,估计你也能大概猜出来IO密集型系统是什么意思。 IO密集型系统大部分时间都在执...
  • Android中bindService是一个异步的过程,什么意思呢? 使用bindService无非是想获得一个Binder服务的Proxy,但这个代理获取到的时机并非由bindService发起端控制,而是由Service端来控制,也就是说bindService之后...
  • Java IO模型总结

    千次阅读 2019-12-11 11:33:49
    异步指的是用户进程触发IO操作后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知异步的特点就是通知)。 什么是阻塞? 所谓阻塞方式的意思是指, 当试图对该文件描述符进行读写时, 如果当时没有...
  • JavaIO学习笔记(五)

    2016-10-01 22:11:00
    异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知异步的特点就是通知什么是阻塞 所谓阻塞方式的意思是指, 当试图对该文件描述符进行读写时, 如果当时没有东西可...
  • 设计模式之reactor、proactor

    千次阅读 2012-07-04 16:43:11
    什么意思呢?我们在编写网络程序的时候很想把网络数据和网络通信本身分离,这样可以很好的调试和分块。 1.典型的reactor模式为当数据来时,通知用户读 2.典型的proactor表现为数据到达时,为上面把数据存好后(当然...
  • Java回调机制

    2021-02-03 11:08:28
    一、Java回调机制是什么意思 Java中的回调机制是什么意思呢?所谓回调:就是A类中调用B类中的某个方法C,然后B类中反过来调用A类中的方法D,D这个方法就叫回调方法。百度百科中对Java回调机制是这样解释的: 软件...
  • 注:面试过程中整理的学习资料,如有侵权联系我即刻删除。 目录 是否了解进程、线程、程序,以及这三者的区别 什么是虚拟内存 IO同步、异步、阻塞、非阻塞 ...死锁是什么意思? 死锁发生的...
  • IO模型指的是在网络数据传输过程中,使用什么通道去发送和接收数据,我们常见的有BIO、NIO、AIO(NIO2.0),我接下来会对这些进行详细的介绍同步/异步/阻塞/非阻塞 到底是什么意思?同步/异步 指的是你去调用一个方法,...
  • 微信开发文档微信开发 notify_url:异步接收微信支付结果通知的回调地址,通知url必须为外... 一开始不懂说的是什么意思,后来经过测试可以使用PUT类型的接口传给商户服务器,服务器会接收到一些要用的信息做之后的处理,
  • 也许有一些同学有这样的疑问:kill -9 PID 中的 -9 到底是什么意思?Ctrl + C 是为什么可以停止掉运行的程序?1. 什么是信号?在计算机科学中,信号是Unix、类Unix以及其他POSIX兼容的操作系统中进程间通讯的一种有...
  • 缘起 笔者最近在看分布式事务的时候发现网上很多资料很零散,不够系统,看的云里雾里,比如在分布式事务...这么多关键词是什么意思?之间又有什么关系??本文旨在带你了解这些花里胡哨的叫法之间的关系,而不是需要...

空空如也

空空如也

1 2 3
收藏数 55
精华内容 22
关键字:

异步通知什么意思