Linux驱动编程之信号机制

编写Linux驱动的过程中,需要考虑与应用程序交互的情况。当设备驱动完成某项任务或者达到某种状态的时候(如设备文件可以写入或读取),此时可以让驱动程序主动通知应用程序进行相应的处理(个人感觉类似于Android应用程序中的广播)。这种在Linux内核中使用的“广播”就是本文要详细介绍的“信号”。

1. Linux信号类型

使用信号进行进程间通信(IPC)是LInux系统的重要通信机制。在Linux系统中,异步通知使用信号来实现。以下是Linux系统支持的信号及其含义:(asm/signal.h)

#define SIGHUP       1
#define SIGINT       2
#define SIGQUIT     3
#define SIGILL       4
#define SIGTRAP     5
#define SIGABRT     6
#define SIGIOT       6
#define SIGBUS       7
#define SIGFPE       8
#define SIGKILL     9
#define SIGUSR1     10
#define SIGSEGV     11
#define SIGUSR2     12
#define SIGPIPE     13
#define SIGALRM     14
#define SIGTERM     15
#define SIGSTKFLT     16
#define SIGCHLD     17
#define SIGCONT     18
#define SIGSTOP     19
#define SIGTSTP     20
#define SIGTTIN     21
#define SIGTTOU     22
#define SIGURG       23
#define SIGXCPU     24
#define SIGXFSZ     25
#define SIGVTALRM     26
#define SIGPROF     27
#define SIGWINCH       28
#define SIGIO         29
#define SIGPOLL     SIGIO
#define SIGPWR       30
#define SIGSYS       31

/* These should not be considered constants from userland.  */
#define SIGRTMIN       32
#define SIGRTMAX       _NSIG

#define SIGSWI       32

注:以上除了SISSTOP和SIGKILL两个信号外,进程可以忽略或捕获其他的全部信号。

如果其中一个信号被捕获,说明在应用程序中为该信号指定了一个处理函数。如果一个信号没有被某个进程捕获,Linux内核会对该信号采用默认处理方式进行处理。

2. 接收Linux信号

在用户程序中,为了捕捉信号,需要使用signal函数来设置信号接收的回调函数:

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

从signal函数原型上看有些复杂, 但主要有两个参数:signum和handler,signum表示信号代码,handler表示回调函数。

在应用程序中捕获信号比较简单,如下例子:

void signal_handler(int signo)
{
        printf("捕获到%d信号\n",signo);
}
main()
{
        printf("信号ID是%d\n",getpid());
        signal(SIGINT, signal_handler);            //设置SIGINT信号的处理函数
        signal(SIGHUP, signal_handler);          //设置SIGHUP信号的处理函数
        signal(SIGQUIT, signal_handler);         //设置SIGQUIT信号的处理函数
       getchar();
}

以上代码示例了如何捕捉信号,并设置相应的处理函数。

3、发送信号

在设备驱动和应用程序的异步通知过程中,驱动程序需要向应用程序发出信号,为了完成发送信号的任务,需要完成以下工作:

  1. 支持F_SETDOWN命令。通过这个命令可以设置file_f_owner为对应进程的ID。
  2. 支持F_SETFL命令的处理。每当FASYNC标志改变时,驱动程序中的fasync函数就会执行。
  3. 再满足条件时,调用kill_fasync函数发送相应的信号。

接收信号可以用signal函数和sigaction函数来完成,他们之间有以下几个区别:
signal函数
1、signal在调用handler之前先把信号的handler指针恢复;sigaction调用之后不会恢复handler指针,直到再次调用sigaction修改handler指针。
:这样,(1)signal就会丢失信号,而且不能处理重复的信号,而sigaction就可以。因为signal在得到信号和调用handler之间有个时间把handler恢复了,这样再次接收到此信号就会执行默认的handler。(虽然有些调用,在handler的以开头再次置handler,这样只能保证丢信号的概率降低,但是不能保证所有的信号都能正确处理)
2、signal在调用过程不支持信号block;sigaction调用后在handler调用之前会把屏蔽信号(屏蔽信号中自动默认包含传送的该信号)加入信号中,handler调用后会自动恢复信号到原先的值。
(2)signal处理过程中就不能提供阻塞某些信号的功能,sigaction就可以阻指定的信号和本身处理的信号,直到handler处理结束。这样就可以阻塞本身处理的信号,到handler结束就可以再次接受重复的信号。

在驱动程序编写过程中与应用程序进行交互是非常重要的,他可以确保用户程序能够顺利执行,也能保证驱动能够更好地服务于用户。以上是本人学习中的一些总结,希望对大家有帮助~~

你可能感兴趣的:(Linux驱动编程之信号机制)