探秘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函数调用和返回的规则,所以处理这些每一个信号都必须使用一些汇编代码。
来硬性的告诉操作系统,这些代码需要得到控制权,此时会从这些静态的代码中获取权限。然后执行。
我们这里的着眼点主要聚焦于软件层面上。
[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);
}
[/c]
查看原文:http://zmrlinux.com/2015/11/20/%e6%8e%a2%e7%a7%98c-signal%e4%bf%a1%e5%8f%b7/