当前位置: 首页 > C, C/C++ > 正文

探秘C-signal信号

探秘C程序中的信号

简单的不多说,也就不进行简单的介绍了。

可移植性:

首先对于<signal.h>中声明的函数不能完全的安全的定义一种可移植的用法,原则上,可以为一个只有raise报告的信号指定一个处理程序,但是很难想象它的那些方面比<setjmp.h>中的跳转函数做得更好,同时也不能保证一个指定的信号在C语言的所有实现中不可能报告,所以不管什么时候程序处理信号,它的可移植性都会受到限制。

C标准库关于信号的一些内容:

在头文件<signal.h>为处理各种各样的信号声明了一个类型和两个函数,并定义了几个宏。

定义类型:

sig_atomic_t  :这个类型的对象可以作为一个原子实体被访问,即使有异步中断发生的时候也是如此。

定义的宏:

SIG_DFL

SIG_ERR

SIG_IGN

这个三个宏展开为具有不同值的常量表达式,且他们的值和所有声明的函数的地址都不相等,下面还有几个宏,都展开为正的数值常数表达式,他们主要针对具体的情况对应的信号。

SIGABRT    异常终止,例如调用了abort()函数

SIGFPE       错误的算术操作,除0或溢出,现在广泛的所有的溢出都报告这个信号

SIGILL        一条无效的函数影像

SIGINT        收到一个交互的提示信号,异步可中断原子操作,若未保存上下文,无法恢复执行

SIGSEGV     对存储器的无效访问,段越界,就是段错误的信号

SIGTERM     送到程序中的终止请求

 

定义的函数

#include <signal.h>

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);        /*信号处理函数*/

int raise(int sig);                                        /*信号发送函数*/

<signal.h>的实现

这里我们依然是为了探秘原理,做一个简单的小例子。

首先说一下硬件信号吧。

硬件信号和我们其他一些软件信号是不同的,在某些系统中,有些代码需要得到控制权,由于这是异步的所以会选择将这些代码添加进signal 中。所以硬件系统或者计算机本身报告的信号,所以这里一定要小心。很多系统都会把控制权转移到指定的地址,但不会遵守C函数调用和返回的规则,所以处理这些每一个信号都必须使用一些汇编代码。

来硬性的告诉操作系统,这些代码需要得到控制权,此时会从这些静态的代码中获取权限。然后执行。

我们这里的着眼点主要聚焦于软件层面上。


#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<signal.h>
#include<string.h>
#include<stdlib.h>

typedef int sig_atomic_t ;
typedef void _sigfun(int);

_sigfun *_sigtable[_NSIG] = {0};

int (raise)(int sig){
sigfun *s;
if(sig <= 0 || _NSIG <= sig)
     return (-1);
if((s = _sigtable[sig]) != SIG_IGN && s != SIG_DFL)
{
        _sigtable[sig] = SIG_DFL;
        (*s)(sig);
}else if(s == SIG_DFL){
        char ac[10],*p;
        switch(sig){
              case SIGABRT:
                   p = "abort";
                   break;
              case SIGFPE:
                   p = "arithmetic error";
                   break;
              case SIGILL:
                   p = "invaild executable code";
                   break;
              case SIGSEGV:
                   p = "termination request";
                   break;
              default :
                   *(p = &ac[(sizeof ac)-1]) = '\0';
                  do{
                      *--p = sig %10 + '0';
 
                    }while((sig /= 10) != 0);
                  fputs("signal #",stderr);
               }
              fputs(p,stderr);
              fputs("----terminating \n",stderr);
              exit(EXIT_FAILURE);
           }
            return 0;
   }

_sigfun * (signal)(int sig,_sigfun *fun)
{
         _sigfun *s;
        if(sig <= 0 || _NSIG <= sig || fun == SIG_ERR)
            return (SIG_ERR);
        s = _sigtable[sig];
        _sigtable[sig] = fun;
        fun(sig);
        return (s);
}

void signalfun(int sig){
       printf("I get the signal and take it\n");
       return ;
}
int main(){
       signal(SIGINT,signalfun);
       kill(getpid(),SIGINT);

}

本文固定链接: http://zmrlinux.com/2015/11/20/%e6%8e%a2%e7%a7%98c-signal%e4%bf%a1%e5%8f%b7/ | Kernel & Me

该日志由 root 于2015年11月20日发表在 C, C/C++ 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: 探秘C-signal信号 | Kernel & Me