4

のシグナルハンドラをインストールするプログラムがありますSIGSEGV。シグナル ハンドラー (クラッシュをキャッチしようとする) で、アプリケーションを再起動します。

しかし、私のアプリケーションが復活すると、それはSIGSEGVもう処理されません。

次に例を示します。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

const char * app = 0;

void sig_handler(int signo)
{
    puts("sig_handler");

    const pid_t p = fork();

    if (p == 0)
    {
        printf("Running app %s\n", app);
        execl(app, 0);
    }

    exit(1);
}


int main(int argc, char** argv)
{
    app = argv[0];

    struct sigaction act;
    sigemptyset(&act.sa_mask);

    act.sa_handler = sig_handler;
    act.sa_flags = 0;

    const int status = sigaction(SIGSEGV, &act, 0) == 0;     
    printf("signaction = %d\n", status);

    sleep(5);

    int* a = 0;
    int b = *a;

    return 0;
}

出力で得られるものは次のとおりです。

./signals 
signaction = 1
sig_handler
Running app ./signals
signaction = 1

したがって、sighandler が正しい方法で設定されていることがわかりますが、復活したアプリは静かにクラッシュしました。

私は何が欠けていますか?

4

1 に答える 1

6

あなたが見逃しているのは、デフォルトでは、シグナルを処理するときに、処理関数が戻るまで、そのシグナルの追加の配信がブロックされることです。execl()シグナルハンドラーから戻ることはないため(代わりに呼び出す)、2番目のハンドラーSIGSEGVは配信されません。シグナルハンドラー関数が戻るまで待機していますが、決して戻りません。

希望どおりの結果を得るには、この既定の動作を変更する必要があります。これを行う最も簡単な方法は、シグナル ハンドラを登録するときに適切なフラグを設定することです。

act.sa_flags = SA_NODEFER;

探していると思われる再帰的な動作が得られます。他のオプションは、通話sigprocmask()の前にブロックを解除することです.execl()

他のいくつかの補助的なポイント:

  1. puts()printf()execl()およびexit()は非同期セーフではなく、シグナル ハンドラーから呼び出すべきではありません。execle()そして_exit()大丈夫でしょう。

  2. あなたはexecl()正しく電話していません。最初の引数はアプリケーション名でなければならないので、execl(app, app, (char *)0);正しいでしょう。省略した to へのキャストchar *が必要です。

于 2016-03-13T22:41:18.323 に答える