Linux下segfault上的自重启程序

Posted

技术标签:

【中文标题】Linux下segfault上的自重启程序【英文标题】:Self restart program on segfault under Linux 【发布时间】:2011-04-11 19:41:06 【问题描述】:

在 Linux 下,程序通过在崩溃处理程序中捕获异常(例如在 segfault 上)在崩溃时重新启动自己的最佳方式是什么?

【问题讨论】:

在这里查看一些答案***.com/questions/2545993/… 【参考方案1】:

最简单的是

while [ 1 ]; do ./program && break; done

基本上,你运行程序直到它返回 0,然后你就中断了。

【讨论】:

这个解决方案和llasram's 可以使故意终止进程变得困难(至少用户最知道发生了什么......)。根据预期用途,这可能是好是坏。 @dmc 当然,最简单的不一定好。如果不了解更多有关需求,就很难说。我喜欢你的回答,因为它更健壮。 哦,我没有抱怨。这具有简单的优点,有时您希望无知的用户将其杀死... @dmckee - llasram's answer 具有父级可以捕获SIGTERM,向子级发出信号,等待,然后有序退出的属性。这个答案应该可以适应做同样的事情——bash 的作业控制应该足够丰富以支持它。 @dmckee 我在重启之前添加了一个sleep 2,这样第二个 Ctrl+C 就会停止无限循环。【参考方案2】:

SIGSEGV 可以被捕获(参见man 3 signalman 2 sigaction),并且程序可以在其自身上调用exec 系列函数之一以重新启动。对于大多数运行时崩溃也是如此(SIGFPESIGILLSIGBUSSIGSYS、...)。

不过,在这样做之前我会考虑一下。对于 unix 程序来说,这是一种相当不寻常的策略,您可能会让您的用户感到惊讶(也不一定以令人愉快的方式)。

无论如何,如果有你想在死前清理的任何资源,请确保不要SIGTERM自动重启,否则愤怒的用户会使用SIGKILL,你会留下一个烂摊子。

【讨论】:

不是一个好主意,来自信号手册页:“根据 POSIX,进程的行为在它忽略不是由 kill(2) 生成的 SIGFPE、SIGILL 或 SIGSEGV 信号后未定义或raise(3)。” @Paul:我以前没有注意到这一点。我不清楚的事情是运行一个处理程序,该处理程序在您复制 argv[0] 的某个静态变量上调用 exec 构成“忽略”信号。我的直觉是声称它没有。无论如何,我已经能够在 Mac OS 和 linux 上可靠地处理 SIGSEGV。我不记得处理过 SIGFPE,而且我认为我没有每个生成的 SIGILL 或 SIGBUS。当然,这里的其他建议很好,可以实现 OP 的愿望,但我从字面上理解了标题。【参考方案3】:

你可以有一个循环,在其中你基本上是fork(),在子进程中做真正的工作,然后等待子进程并检查它在父进程中的退出状态。您还可以使用以类似方式监视和重新启动程序的系统,例如 daemontools、runit 等。

【讨论】:

【参考方案4】:

作为对这里提议的补充:

另一个选择是像 getty 守护进程那样做。请参阅 /etc/inittab 和相应的 inittab(5) 手册页。它似乎是最全系统的平均值 ;-)。

它可能看起来像下面的文件片段。明显的优势,这种方法是相当标准的,它允许通过运行级别控制你的守护进程。

# Run gettys in standard runlevels
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6

【讨论】:

这是正确的做法。【参考方案5】:

进程无法自行重新启动,但您可以使用crontab(1) 之类的实用程序来安排脚本以定期检查进程是否仍处于活动状态。

【讨论】:

没有什么能阻止程序在argv[0] 上调用exec(几乎总是它自己的可执行文件)... “崩溃”是操作系统发送信号(默认行为“终止进程”)。默认行为可以替换为用户定义的函数... 如果内存严重损坏以至于您在 SEGV 处理程序中获得了第二个 SEGV,该怎么办?从本质上讲,从另一个进程操作更可靠。 我同意@dmckee,AFAIK 调用 exec 基本上是另一个具有相同 PID 的进程。它重生,所有内存都丢失了(不确定共享内存和类似资源是否有任何问题需要显式清理)[只要你复制 argv[0] 的内存是干净的,你应该是好的]跨度> @dmckee 如何替换默认行为?可以从程序内部完成吗?我的意思是,程序是否可以捕获自身崩溃然后重新启动。【参考方案6】:

程序本身显然不应该检查它是否正在运行:)

大多数企业解决方案实际上只是从ps() 为给定字符串提取输出的奇特方式,并在满足某些条件时执行操作 - 即如果找不到您的流程,则调用启动脚本.

【讨论】:

【参考方案7】:

如果它特定于段错误,请尝试以下代码。这可以根据需要进行修改。

#include <stdio.h> 
#include <signal.h> 
#include <setjmp.h> 
#include <poll.h>

sigjmp_buf buf; 
void handler(int sig)  
siglongjmp(buf, 1); 
 
int main()  
//signal(SIGINT, handler); 
//register all signals
struct sigaction new_action, old_action;
new_action.sa_handler = handler;
sigemptyset (&new_action.sa_mask);
new_action.sa_flags = 0;

sigaction (SIGSEGV, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
sigaction (SIGSEGV, &new_action, NULL);

if (!sigsetjmp(buf, 1))
printf("starting\n"); 
//code or function/method here

else  
printf("restarting\n"); 
 //code or function/method here

while(1) 
poll(NULL,0,100); //ideally use usleep or nanosleep. for now using poll() as a timer
printf("processing...\n");

return 0; //or exit(SUCESS)

【讨论】:

以上是关于Linux下segfault上的自重启程序的主要内容,如果未能解决你的问题,请参考以下文章

99.Shell脚本自启程序并监控(实现全自动监控服务)

gcc+mingw 下的 C++ segfault 但不是 gcc+linux

glDrawArrays上的OpenGL Segfaulting

Android 上的 QApplication,从 JNI 开始,一直到 SEGFAULT

std::vector push_back 上的 Segfault/“向量不可解引用”

Linux 中的 Segfault,在 Mac OS 上运行良好