系统相关
首页 > 系统相关> > Mini2440之linux驱动移植-信号驱动IO模型

Mini2440之linux驱动移植-信号驱动IO模型

作者:互联网

在上一节中我们介绍了linux下的五种IO模型:

并介绍了poll机制在按键驱动中的使用,这一节我们将重点介绍信号驱动IO模型如何在按键驱动的例子中的使用。

一、信号驱动IO模型

1.1 什么是信号驱动IO模型

我们举个例子,我们在钓鱼的时候需要不停的查看鱼竿,看看有没有鱼咬鱼浮了,这导致我们不能去做其他的事情,显然这是一个阻塞IO模型。

如果我们给鱼竿安装一个报警器,当鱼浮下沉的时候,也就说明有鱼儿咬钩了,就立刻报警。我们收到报警信号之后,去把鱼钓上来。映射到linux操作系统中,这就是信号驱动IO模型。

其实这个就有点类似事件监听模型。应用程序预先在内核中注册一个信号处理函数,本质就是一个回调函数,当IO准备好之后(读:有数据可读;写:有空间可写),内核就会给进程发送一个预先预定号的信号,进程在收到信号后,就调用信号对应的处理函数。

1.2 什么是信号

信号是linux系统响应某些条件而产生的一个事件,它可以用于进程之间的通信。

信号是在软件层次上对中断机制的一种模拟,在原理上,一个信号接收到一个信号与处理器接收到一个中断请求可以说是一样的。

信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。那么,进程是如何发现和接受信号呢?

实际上,信号的接收不是由用户进程来完成的,而是由内核代理。当一个进程P2向另一个进程P1发送信号后,内核接受到信号,并将其放在P1的信号队列当中。当P1再次进入内核态时,会检查信号队列,并根据相应的信号调取相应的信号处理函数。

信号是进程间通信机制中唯一的异步通信机制,可以看做是异步通知,通知接收信号的进程有哪些事情发生了。信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息。

1.3 信号来源

信号事件的发生有两个来源:

1.4 linux产生信号的条件

(1) 当用户按下某些终端键时,将产生信号

(2) 硬件异常将产生信号

比如数据运算时,除数为0;或者无效的内存访问等;这些条件通常由硬件检测到,并通知内核,然后内核为该条件发生时正在运行的进程产生适当的信号;

(3) 软件异常将产生信号

当检测到某种软件条件已发生,并将其通知有关进程时,产生信号;

(4) 调用 kill函数将发送信号。

注意:接收信号进程和发送信号进程的所有者必须相同,或发送信号进程的所有者必须是超级用户;

(5) 运行shell  kill 命令将发送信号

此程序实际上是使用 kill 函数来发送信号。也常用此命令终止一个失控的后台进程;

1.5 信号的捕获和处理

刚才我们说,当进程P1再次进入内核时,会检查信号队列。那么,进程P1什么时候会再次进入内核呢?进入内核后在什么时机会检测信号队列呢?

发现信号后,根据信号向量,就找到了信号处理函数,然后从内核态跑到用户态去执行信号处理程序,那么用户进程一般如何处理信号?用户进程可按照下列3中方式来处理:

Linux究竟采用上述三种方式的哪一个来响应信号,取决于传递给相应API函数的参数。

二、linux中的信号

2.1 系统支持信号

那么我们就需要知道在linux系统中有哪些可用的信号,在linux终端输入kill -l可以查看系统所支持的信号,可以看出,每个信号的名字都是以SIG开头:

root@zhengyang:/work/sambashare/linux-5.2.8# kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

 在头文件/usr/include/bits/signum.h中,这些信号都被定义为正整数,即每个信号和一个数字编码相对应:

/* Signals.  */
#define SIGHUP          1       /* Hangup (POSIX).  */
#define SIGINT          2       /* Interrupt (ANSI).  */
#define SIGQUIT         3       /* Quit (POSIX).  */
#define SIGILL          4       /* Illegal instruction (ANSI).  */
#define SIGTRAP         5       /* Trace trap (POSIX).  */
#define SIGABRT         6       /* Abort (ANSI).  */
#define SIGIOT          6       /* IOT trap (4.2 BSD).  */
#define SIGBUS          7       /* BUS error (4.2 BSD).  */
#define SIGFPE          8       /* Floating-point exception (ANSI).  */
#define SIGKILL         9       /* Kill, unblockable (POSIX).  */
#define SIGUSR1         10      /* User-defined signal 1 (POSIX).  */
#define SIGSEGV         11      /* Segmentation violation (ANSI).  */
#define SIGUSR2         12      /* User-defined signal 2 (POSIX).  */
#define SIGPIPE         13      /* Broken pipe (POSIX).  */
#define SIGALRM         14      /* Alarm clock (POSIX).  */
#define SIGTERM         15      /* Termination (ANSI).  */
#define SIGSTKFLT       16      /* Stack fault.  */
#define SIGCLD          SIGCHLD /* Same as SIGCHLD (System V).  */
#define SIGCHLD         17      /* Child status has changed (POSIX).  */
#define SIGCONT         18      /* Continue (POSIX).  */
#define SIGSTOP         19      /* Stop, unblockable (POSIX).  */
#define SIGTSTP         20      /* Keyboard stop (POSIX).  */
#define SIGTTIN         21      /* Background read from tty (POSIX).  */
#define SIGTTOU         22      /* Background write to tty (POSIX).  */
#define SIGURG          23      /* Urgent condition on socket (4.2 BSD).  */
#define SIGXCPU         24      /* CPU limit exceeded (4.2 BSD).  */
#define SIGXFSZ         25      /* File size limit exceeded (4.2 BSD).  */
#define SIGVTALRM       26      /* Virtual alarm clock (4.2 BSD).  */
#define SIGPROF         27      /* Profiling alarm clock (4.2 BSD).  */
#define SIGWINCH        28      /* Window size change (4.3 BSD, Sun).  */
#define SIGPOLL         SIGIO   /* Pollable event occurred (System V).  */
#define SIGIO           29      /* I/O now possible (4.2 BSD).  */
#define SIGPWR          30      /* Power failure restart (System V).  */
#define SIGSYS          31      /* Bad system call.  */

下面给出一些信号的描述信息:

信号名称说明
 SIGHUP  1  连接挂断
SIGINT 2 终端中断
SIGQUIT 3 终端退出
SIGILL 非法指令
SIGABRT 5 跟踪陷阱
SIGIOT 6 IOT陷阱
SIGBUS 7 BUS错误
SIGFPE 8 浮点运算异常
SIGKILL 9 终止进程(不能被捕获或忽略)
SIGUSR1 10 用户定义信号1
SIGSEGV 11 无效内存段访问
SIGUSR2 12 用户定义信号2
SIGPIPE 13 向无读进程的管道写数据
SIGALRM 14 超时警告
SIGTERM 15 终止
SIGSTKFLT 16 堆栈错误
SIGCHLD 17 子进程已经停止或退出
SIGCONT 18 如果停止了,继续执行
SIGSTOP 19 停止执行(不能被捕获或忽略)
SIGTSTP 20 终端停止信号
SIGTTIN 21 后台进程需要从终端读取命令
SIGTTOU 22 后台进程需要从终端写出
SIGURG 23 紧急的套接字事件
SIGXCPU 24 超额使用CPU分配的时间
SIGXFSZ 25 文件尺寸超额
SIGVTALRM 26 虚拟时钟信号
SIGPROF 27 时钟信号描述
SIGWINCH 28 窗口尺寸变化
SIGIO 29 I/O
SIGPWR 30 断电重启
SIGSYS 31 系统调用错误

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

2.2 信号分类

linux信号又可以按照可靠性以及实时性两个维度进行分类。

按照可靠性分类:

在早期的UNIX中信号是不可靠的,不可靠在这里指的是:信号可能丢失,一个信号发生了,但进程却可能一直不知道这一点。

现在Linux 在SIGRTMIN信号之前的都叫不可靠信号,这里的不可靠主要是不支持信号队列,就是当多个信号发生在进程中的时候(收到信号的速度超过进程处理的速度的时候),这些没来的及处理的信号就会被丢掉,仅仅留下一个信号。

可靠信号是多个信号发送到进程的时候(收到信号的速度超过进程处理信号的速度的时候),这些没来的及处理的信号就会排入进程的信号队列。等进程有机会来处理的时候,依次再处理,信号不丢失。

按照实时性分类:

非实时信号都不支持信号队列,都是不可靠信号;实时信号都支持信号队列,都是可靠信号。

三、信号的安装

在用户进程中,如果想要处理某一种信号,就需要在进程中安装该信号。安装信号主要用来确定信号值及进程针对该信号值的动作之间的映射关系,即进程将要处理哪个信号;该信号被传递给进程时,将执行何种操作。

linux中有两个函数实现信号的安装:

3.1 signal函数

在用户进程中,可以使用signal函数来设置对应信号的处理函数:

typedef void (*__sighandler_t) (int);
__sighandler_t signal (int __sig, __sighandler_t __handler);

首先定义一个函数指针sighandler_t,参数类型为int,没有返回值;

然后定义signal函数,可以看到该函数:

比如SIG_DEF定义为,即指向地址0:

#define SIG_DFL ((__sighandler_t) 0)

函数返回一个函数指针,类型为sighandler_t。如果signal调用成功,返回上一次为安装信号__sig而调用signal时指定的__handler值;失败则返回SIG_ERR。

然后演示如何使用,我们编写一个示例程序,在程序中,我们捕获SIGINT信号,然后输出"catch the signal SIGINT 信号值":

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>

void sig_handler(int signo);
int main(void)
{
    printf("mian is waiting for a signal\n");
    if(signal(SIGINT,sig_handler) == SIG_ERR){
        perror("signal errror");
        exit(EXIT_FAILURE);
    }
    for(; ;);//有时间让我们发送信号


    return 0;
}

void sig_handler(int signo)
{
    printf("catch the signal SIGINT %d\n",signo);
}

使用gcc编译,然后在ubuntu系统运行:

root@zhengyang:/work/sambashare# ./hello
mian is waiting for a signal
^Ccatch the signal SIGINT 2
^Ccatch the signal SIGINT 2
^Ccatch the signal SIGINT 2
^Ccatch the signal SIGINT 2
^Ccatch the signal SIGINT 2
已杀死

每当我们按下CTRL+C就会发送SIGINT信号,从而执行我们安装的信号处理函数,而当我们重新打开一个终端执行kill  -9 进程号时,发送信号值为9的信号SIGKILL,执行系统默认处理函数,退出进程。

3.2 sigaction函数

int sigaction (int __sig, const struct sigaction * __act,
                     struct sigaction * __oact) 

其中:

如果把第二、第三个参数都设为NULL,那么该函数可用于检查信号的有效性;

第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些函数等等。sigaction结构定义如下:

struct sigaction {
   union{
        void     (*sa_handler)(int);//信号处理程序 不接受额外数据
        void     (*sa_sigaction)(int, siginfo_t *, void *);//信号处理程序,能接受额外数据,可以和sigqueue配合使用
    }_u;
    sigset_t   sa_mask;
    int        sa_flags;//影响信号的行为SA_SIGINFO表示能接受数据
    void     (*sa_restorer)(void);//废弃
};

其中:

更多相关内容参考linux系统编程之信号(六):信号发送函数sigqueue和信号安装函数sigactionLinux 改进捕捉信号机制(sigaction,sigqueue)

四、信号的发送

发送信号的主要函数有:kill、raise、sigqueue、alarm、setitimer以及abort。

在第三节中我们已经介绍了如何给一个用户进程安装信号以及信号对应的处理函数,在这一节我们将介绍进程P2如何向进程P1发送信号。

4.1 kill

4.2 raise

4.3 sigqueue

4.4 alarm

4.5 setitimer

4.6 abort

参考文章:

[1]六、Linux驱动之异步通知

[2]Linux信号驱动I/O 学习记录

[3]linux内核剖析(九)进程间通信之-信号signal(部分转载)

[4]Linux进程间通信之信号 

[5]linux 信号安装、signal、kill,arise讲解

标签:__,IO,signal,Mini2440,信号,进程,驱动,SIGRTMIN,define
来源: https://www.cnblogs.com/zyly/p/15906534.html