2008-09-19 24 views
4

如果我们的程序中发生了段错误,我想捕获SIGSEGV并让用户(可能是GUI客户端)知道一个严重的返回码问题发生了。同时,我想在命令行上显示信息以显示哪个信号被捕获。便携式的方式来捕捉信号并向用户报告问题

今天,我们的信号处理程序如下所示:

void catchSignal (int reason) { 
    std :: cerr << "Caught a signal: " << reason << std::endl; 
    exit (1); 
} 

我可以听到恐怖的尖叫声与上面,因为我已经从这个thread,它是邪恶的阅读从一个调用非重入函数信号处理器。

是否有一种便携的方式来处理信号并向用户提供信息?

编辑:或者至少在便携式POSIX框架内?

回答

12

table列出了所有POSIX保证是异步信号安全的,这样的功能可以从信号处理函数中调用。

通过使用“写”命令从该表中,下面的比较“丑陋”的解决方案希望将这样的伎俩:

#include <csignal> 

#ifdef _WINDOWS_ 
#define _exit _Exit 
#else 
#include <unistd.h> 
#endif 

#define PRINT_SIGNAL(X) case X: \ 
      write (STDERR_FILENO, #X ")\n" , sizeof(#X ")\n")-1); \ 
      break; 

void catchSignal (int reason) { 
    char s[] = "Caught signal: ("; 
    write (STDERR_FILENO, s, sizeof(s) - 1); 
    switch (reason) 
    { 
    // These are the handlers that we catch 
    PRINT_SIGNAL(SIGUSR1); 
    PRINT_SIGNAL(SIGHUP); 
    PRINT_SIGNAL(SIGINT); 
    PRINT_SIGNAL(SIGQUIT); 
    PRINT_SIGNAL(SIGABRT); 
    PRINT_SIGNAL(SIGILL); 
    PRINT_SIGNAL(SIGFPE); 
    PRINT_SIGNAL(SIGBUS); 
    PRINT_SIGNAL(SIGSEGV); 
    PRINT_SIGNAL(SIGTERM); 
    } 

    _Exit (1); // 'exit' is not async-signal-safe 
} 

编辑:大厦的窗户。

尝试构建这个窗口后,看起来'STDERR_FILENO'没有被定义。然而从文档看,它的值看起来是'2'。

#include <io.h> 
#define STDIO_FILENO 2 

编辑:“退出”不应从信号处理程序或者叫!

正如所指出的fizzer,调用_Exit在上述用于信号如HUP和TERM大锤的方法。理想情况下,当捕获这些信号时,可以使用“volatile sig_atomic_t”类型的标志通知主程序它应该退出。

以下我发现在我的搜索中很有用。

  1. Introduction To Unix Signals Programming
  2. Extending Traditional Signals
+0

很好的回答,从中学到了一些新东西,太糟糕了原来的海报没有回来投票/选择一个答案:) – 2008-09-22 00:46:54

+0

感谢您的评论。顺便说一句 - 这*是OP的答案,即。我。我仍然不能100%确定这是正确的,因此我不会将它标记为已回答。 – 2008-09-22 07:49:20

0

编写一个启动程序来运行程序并向用户报告异常退出码。

1

FWIW,2是Windows标准的错误还可以,但你会需要一些条件编译,因为他们写()被调用_write()。你也想要

#ifdef SIGUSR1 /* or whatever */ 

等围绕所有引用的信号不保证由C标准定义。

此外,如上面提到的,你不想处理SIGUSR1,SIGHUP,SIGINT,SIGQUIT和SIGTERM这样。

1

理查德,仍然没有足够的业力评论,所以一个新的答案我害怕。这些是异步信号;你不知道它们何时交付,所以可能你会在图书馆代码中需要完成以保持一致。这些信号的信号处理程序因此需要返回。如果你调用exit(),库会在post-main()中做一些工作,包括调用使用atexit()注册的函数并清理标准流。如果您的信号到达标准库I/O功能,则此处理可能失败。因此在C90中不允许调用exit()。我现在看到C99通过在stdlib.h中提供了一个新的函数_Exit()来放宽要求。 _Exit()可以安全地从异步信号的处理程序中调用。 _Exit()不会调用atexit()函数,并且可能会在执行时酌情忽略清理标准流。

给bk1e(注释几个帖子) SIGSEGV是同步的事实是为什么你不能使用没有设计为可重入的函数。如果崩溃的函数持有一个锁,并且信号处理程序调用的函数试图获取相同的锁,该怎么办?

这是一种可能性,但它不是“SIGSEGV是同步的”这是问题。从处理程序调用非重入函数是异步信号要差,原因有二多:

  • 异步信号处理程序是 (一般),希望能回来, 恢复正常的程序执行。一个 同步信号的处理程序是 (通常)无论如何将终止 ,所以如果你失败了 ,你并没有损失太多。您可以绝对控制同步信号的传输时间 - 它会在您执行缺陷代码时发生,并且不会在其他时间发生。异步信号传送时,您无法控制。除非OP自己的I/O代码本身是缺陷的原因 - 例如输出一个坏字符* - 他的错误信息有一个合理的成功机会。