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 signal
或man 2 sigaction
),并且程序可以在其自身上调用exec
系列函数之一以重新启动。对于大多数运行时崩溃也是如此(SIGFPE
、SIGILL
、SIGBUS
、SIGSYS
、...)。
不过,在这样做之前我会考虑一下。对于 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上的自重启程序的主要内容,如果未能解决你的问题,请参考以下文章
gcc+mingw 下的 C++ segfault 但不是 gcc+linux
glDrawArrays上的OpenGL Segfaulting
Android 上的 QApplication,从 JNI 开始,一直到 SEGFAULT