我是靠谱客的博主 单薄纸鹤,最近开发中收集的这篇文章主要介绍异步通知1. 信号:2. 信号的接收:3. 信号的释放:,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

在设备驱动中使用异步通知可以使得对设备的访问可进行时,由驱动主动通知应用程序进行访问。这样,使用无阻塞 I/O 的应用程序无需轮询设备是否可访问,而阻塞访问也可以被类似“中断”的异步通知所取代。

 

1. 信号:

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

信号含义
SIGHUP1挂起
SIGINT(ctrl+c)2终端中断
SIGQUIT3终端退出
SIGILL4无效命令
SIGTRAP5跟踪陷阱
SIGIOT6IOT 陷阱
...  
SIGKILL9强行终止(不能被捕获或忽略)
SIGTERM15终止
SIGCHLD17子进程已经停止或退出
SIGSTOP19停止执行(不能被捕获或忽略)
SIGIO29I/O

 

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

 

2. 信号的接收:

用户程序中,定义信号的处理函数用如下函数:

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

第一个参数,指定信号的值,就是上边 SIGCHLD 之类的宏的值

第二个参数,指定针对前边信号值的处理函数

    SIG_IGN,忽略信号

    SIG_DFL,系统默认的方式处理

用户自定义函数,信号捕捉后函数被执行

返回值:

成功,函数的返回值

失败,SIG_ERR

 

一个用 ctrl+c 触发到自己的函数中的例子:

 sigterm_handler( signo)
{
("Have caught sig N.O. %dn", signo);
exit(0);
}
()
{
signal(SIGINT, sigterm_handler);
while(1);
return 0;
} 

一个用实现输入字符,打印字符异步的例子:

 #include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#define MAX_LEN 100
input_handler( num)
{
char data[MAX_LEN];
len;
/* 读取并输出 STDIN_FILENO 上的输入 */
len = read(STDIN_FILENO, &data, MAX_LEN);
data[len] = 0;
("input available:%sn", data);
}
()
{
oflags;
/* 启动信号驱动机制 */
signal(SIGIO, input_handler);
fcntl(STDIN_FILENO, F_SETOWN, getpid());
oflags = fcntl(STDIN_FILENO, F_GETFL);
fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC);
/* 最后进入一个死循环,仅为保持进程不终止,如果程序中
没有这个死循会立即执行完毕 */
while (1);
} 

程序解释:

主函数中:

①为 SIGIO 信号安装 input_handler()作为处理函数

②fcntl(STDIN_FILENO, F_SETOWN, getpid()); 设置本进程为STDIN_FILENO 文件的拥有者(owner)

③对设备设置 FASYNC 标志

运行结果:

> ./signal_test

I am Chinese.

input available: I am Chinese.

I love Linux driver.

input available: I love Linux driver.

需要注意的是:当用户输入完字符串的时候,才会触发 SIGIO 的信号

 

用户空间实现异步通知的 3 项工作:

  1. 通过 F_SETOWN IO 控制命令设置设备文件的拥有者为本进程,这样从设备驱动发出的信号才能被本进程接收到。 
  2. 通过 F_SETFL IO 控制命令设置设备文件支持 FASYNC,即异步通知模式。 
  3. 通过 signal()函数连接信号和信号处理函数。

3. 信号的释放:

在设备驱动和应用程序的异步通知交互中,需要应用程序捕捉信号,驱动程序释放信号。

 

所涉及的 3 项工作:

  1. 支持 F_SETOWN 命令,能在这个控制命令处理中设置 filp->f_owner 为对应进程 ID。不过此项工作已由内核完成,设备驱动无需处理。 
  2. 支持 F_SETFL 命令的处理,每当FASYNC 标志改变时,驱动程序中的fasync()函数将得以执行。因此,驱动中应该实现 fasync()函数。 
  3. 在设备资源可获得时,调用 kill_fasync()函数激发相应的信号。

可以看出,上述的3项工作和应用程序中的3项是对应的,他们之间的关系,如下图表现的很好:

 

 

在设备驱动中异步编程主要涉及一个数据结构、两个函数

一个数据结构:

fasync_struct 不需要知道具体的内容,只需要作为一个参数传递给 fasync_helper 就可以了

两个函数:

处理 FASYNC 标志的变更

fasync_helper( fd, struct file *filp, mode, struct fasync_struct **fa);

    前三个参数,直接使用 static xxx_fasync( fd, struct file *filp, mode) 中的参数

    fa,由用户定义的 fasync_struct 的机构体的指针

释放信号

 

kill_fasync(struct fasync_struct **fa, sig, band);

    fa,由用户定义的 fasync_struct 的机构体的指针

    sig,信号的号 / 表征信号的宏

    band,POLL_IN,可读。POLL_OUT,可写

一般的格式和有关此部分的例子:

static xxx_fasync( fd, struct file *filp, mode)

{

    struct xxx_dev *dev = filp->private_data;

    return fasync_helper(fd, filp, mode, &dev->async_queue);

}

static ssize_t xxx_write(struct file *filp, const char __user *buf, size_t count,

loff_t *f_pos)

{

    struct xxx_dev *dev = filp->private_data;

    ...

    /* 产生异步读信号 */

    (dev->async_queue)

    kill_fasync(&dev->async_queue, SIGIO, POLL_IN);

    ...

}

static xxx_release(struct inode *inode, struct file *filp)

{

    /* 将文件从异步通知列表中删除 */

    xxx_fasync(-1, filp, 0);

    ...

    return 0;

}

 

 

 

最后

以上就是单薄纸鹤为你收集整理的异步通知1. 信号:2. 信号的接收:3. 信号的释放:的全部内容,希望文章能够帮你解决异步通知1. 信号:2. 信号的接收:3. 信号的释放:所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(60)

评论列表共有 0 条评论

立即
投稿
返回
顶部