我在信号到C处理在新的Unix和我一直在寻找它的一些教程(纯粹出于兴趣)。
我的问题是,是否有可能继续过去点的节目,其中一个信号进行处理的执行?
据我所知,信号处理功能确实清除但在异常处理(如在C ++)的精神,有可能是该信号以相同的方式和程序继续运行正常处理?
目前catch
进入无限循环(可能的方式退出将调用exit(1)
我打算将是b
被分配1和用于该程序正常完成(如果可能的话当然)。
这里是我的代码:
#include <signal.h>
#include <stdio.h>
int a = 5;
int b = 0;
void catch(int sig)
{
printf("Caught the signal, will handle it now\n");
b = 1;
}
int main(void)
{
signal(SIGFPE, catch);
int c = a / b;
return 0;
}
此外,由于C是程序性的,怎么来的信号处理程序声明之前,后者已被执行之后实际上是所谓有问题的声明?
最后,为了使处理功能做了正确的清理,比需要在异常的情况下,被清理的所有变量需要先于函数声明,对不对?
在此先感谢您的回答,并道歉,如果上面的一些内容是非常明显的。
是的,这就是信号处理程序是。 但有些信号需要为了让程序继续运行(例如SIGSEGV,SIGFPE,...)特别处理。
见手册页sigaction
:
根据POSIX,它忽略了不是由杀(2)产生或提高(3)SIGFPE,SIGILL或SIGSEGV信号之后的过程的行为是未定义的。 整数被零除未定义的结果。 在某些体系结构将产生SIGFPE信号。 (也将所述最负整数由-1可以生成SIGFPE。)忽略该信号可能会导致无限循环。
现在, 您忽略的信号,通过没有做任何事情,以防止它发生(再次)。 您需要在信号处理程序的执行上下文和手动修复它,这涉及到覆盖一些寄存器。
如果在其中sa_flags指定SA_SIGINFO,然后sa_sigaction(而不是sa_handler)指定为正负号的信号处理功能。 该函数接收信号编号作为第一个参数,一个指向siginfo_t作为第二个参数和一个指向ucontext_t(转换为void *)作为其第三个参数。 (通常,处理函数不作任何使用第三个参数。见的getContext(2)有关ucontext_t进一步的信息。)
上下文允许访问寄存器,在故障发生时,需要修改,允许程序继续进行。 看到这个LKML职位 。 由于有提到, siglongjmp
也可能是一种选择。 该帖子还提供了处理错误相当重用的解决方案,而无需进行变量的全局等:
因为你处理它youself,你有你想要的任何灵活性的错误处理。 例如,可以使故障处理程序跳转到像这样的东西你的功能有些指定点:
__label__ error_handler;
__asm__("divl %2"
:"=a" (low), "=d" (high)
:"g" (divisor), "c" (&&error_handler))
... do normal cases ...
error_handler:
... check against zero division or overflow, so whatever you want to ..
然后,你的SIGFPE处理程序只需要像做
context.eip = context.ecx;
在一般情况下,是的,执行处理程序返回后继续。 但是,如果信号是由硬件错误引起的 (如浮点异常或分段错误),你有没有撤消的错误的方式,所以你的程序将被终止无关。
换句话说,你有信号和事情,导致信号之间进行区分。 通过自身的信号是完全正常和handlable,但他们并不总是让你修正导致信号错误 。
(有些信号是特殊的,比如ABRT和停止,因为即使你只是手动提出这样的信号与感测kill
,你仍然不能“阻止它的作用。”当然KILL甚至不能在所有的处理。 )
如果你知道你在做什么,你可以设置指令指针违规的指令后,正确地指出。 下面是我在x86(32位和64位)的例子。 在家里或在真正的产品不要轻易尝试!
#define _GNU_SOURCE /* Bring REG_XXX names from /usr/include/sys/ucontext.h */
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ucontext.h>
static void sigaction_segv(int signal, siginfo_t *si, void *arg)
{
ucontext_t *ctx = (ucontext_t *)arg;
/* We are on linux x86, the returning IP is stored in RIP (64bit) or EIP (32bit).
In this example, the length of the offending instruction is 6 bytes.
So we skip the offender ! */
#if __WORDSIZE == 64
printf("Caught SIGSEGV, addr %p, RIP 0x%lx\n", si->si_addr, ctx->uc_mcontext.gregs[REG_RIP]);
ctx->uc_mcontext.gregs[REG_RIP] += 6;
#else
printf("Caught SIGSEGV, addr %p, EIP 0x%x\n", si->si_addr, ctx->uc_mcontext.gregs[REG_EIP]);
ctx->uc_mcontext.gregs[REG_EIP] += 6;
#endif
}
int main(void)
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = sigaction_segv;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
/* Generate a seg fault */
*(int *)NULL = 0;
printf("Back to normal execution.\n");
return 0;
}