Linuxアプリケーションの開発と信号処理

Linuxアプリケーションの開発と信号処理

現在、ユーザーが自分のアプリが終了していると文句を言う問題があります。特定の(ランダムに見える)条件およびデスクトップ環境では、アプリケーションは終了せず、再起動時に設定は保存されません。私は関連IRCチャネルに連絡しましたが、ほとんどの場合、信号を正しく処理するように言われました。端末のCtrl-CについてはSIGINTを知り、「正常な」終了についてはSIGTERMを知っています。しかし、SIGHUPも重要だと聞きました。だから私の質問は次のようになります

正しく動作するアプリケーションを構築するには、どの信号を処理する必要がありますか?

答え1

https://en.wikipedia.org/wiki/Unix_signal

標準信号と基本動作のリストがあります。十分な権限を持つプロセスは常にユーザーにシグナルを送信できますが、プロセス(またはプロセスを介してユーザー)はそうしないでください。

あなたはあなたのプロセスが使用することを期待してkill使用する必要がありますkill学期送信する特定の信号をターゲットが処理しているかどうかを知らない限り、環境(シェル、ターミナルドライバ)によって生成される可能性がある複数の信号。

基本信号をタスクごとに並べ替えることができます。

コアダンプ信号

ABRT TRAP SYS BUS FPE ILL SEGV   XFSZ XCPU QUIT

一部の特殊機能(TRAP、ABRT、SYS)を使用するか、ハードエラー状態(BUS、FPE、ILL、SEGV)を入力することによって生成されます。 QUITコアダンプが必要な端末でユーザーが生成します(C+\)。

デフォルト設定のままにしておくこともできます。

アウト終了信号:

HUP INT PIPE TERM ALRM POLL PROF USR1 USR2

あなたは期待する必要があります

HUP INT PIPE TERM

さまざまな状況で環境がどのように見えるかによって:

HUP -- when the terminal hungs up or you become a stopped orphaned process
INT -- when the user at the terminal interrupts you with C-c
PIPE -- when a PIPE or socket you write into closes, e.g. by
        exiting before you finished writing to it 
       (`yourprogram | (exit)` will give you a `PIPE` 
        if yourprogram attempts to write to its STDOUT) 
TERM -- when a process ends you a normal termination request

残りの終了信号は、直接設定した場合にのみ受信する必要があります。

殺すそして止めるあなたができることは何もありません。

端末の生成を傍受したい場合があります。停止信号:

TTIN -- you read from the terminal and you're a backgrounded process
TTOU -- you write the terminal when you're a backgrounded process
        and the terminal is set to put you to sleep when you do
TSTP -- you're being put to sleep with `C-Z`

しかし、最悪の場合、これはあなたの地位を破壊することなくあなたの進行を中断するだけです。

CHLDCONTまたはを処理する必要があることを知らない限り、それはURG必要ありません。

簡単に言うと:

基本的に、通常、事前終了クリーンアップを実行するには、HUP、INT、PIPE、およびTERMを処理(または無視)する必要があると思います。プログラムがこれらの信号を使用しない場合、またはすべての場合に絶対にクリーンアップが必要な場合を除き、残りはそのままにすることができます。

後者の場合、未処理のすべての信号を空白でブロックできますが、信号ブロックマスクは分岐呼び出しとexecve呼び出しの間に継承され、ILLなどの信号は処理中に無視またはブロックされます。実行時に生成して送信しません。 killまたはsigqueueを介してそれらを渡すと、未定義の動作が発生します。

詳しくは、マンページと標準をご覧ください。シグナルはUnixで非常に大きなトピックであり、それを扱うのは難しいかもしれません。

答え2

これにより、そのうちの1つがプログラムを終了するため、多数の信号を無視できます。 sblingxがコメントで提案したように、最良の方法は、これらの信号を分析し、信号がどこから来るのかを理解することです。結局のところ、あなたのプログラムはおそらく合理的な理由で終了したでしょう。

そう言うと、次のことがわかります。signals(7)プロセスの終了を引き起こす可能性がある信号のリストを取得します。

SIGHUP、SIGINT、SIGQUIT、SIGILL、SIGABRT、SIGFPE、SIGKILL、SIGSEGV、SIGPIPE、SIGALRM、SIGTERM、SIGUSR1およびSIGUSR2.

アプリケーションが端末に接続するのに時間がかかる場合は、処理することをお勧めしSIGINTます(最終的にはCtrl+は非常に有名です)。また、これはまだ基本的なシャットダウン信号であり、カーネルで使用されるため(システムがシャットダウンしたときなど)、良いアイデアです。おそらくコアダンプを引き起こすので、最初の2つのバージョンよりも「より難しい」バージョンです。このメッセージを受信すると、プログラムはすぐに中断される可能性があります。追加情報を受け取った後、プログラムは「混乱をクリーンアップして消えます」(設定を保存して適切に終了します)。CSIGTERMSIGQUIT

SIGILL、、、SIGFPEおよびSIGSEGVSIGPIPEプログラムの誤動作に関連する信号です。セグメンテーションエラーおそらく最も一般的なケースです。しかし、最終的にこれらのケースはすべてエラーと見なすことができ、信号をキャッチすることがそのような場合を回復する最善の方法ではないと思います。

  • ほとんどの場合、コンパイラはSIGILLこれらのことが簡単に発生することを許可しません(ここでもっと学ぶ)だからこれは別に残してもいいと思います。
  • ほとんどのsを避けるために絶対にゼロに分割しないでくださいSIGFPE。それ以外の場合は、プログラムが数学に堪能で数字に夢中でないことを確認してください。
  • SIGSEGVgdbこれはさまざまな理由(不正なメモリアクセス、不正な逆参照)が原因で発生する可能性があります。そのために、プログラムの実行中にプログラムを監視し、不快なコマンドのスタックトレースを使用することをお勧めします。gdb
  • 最後に、SIGPIPE主にデータフロー(ファイルの読み取り、接続...)に関連しています。プログラムI / Oストリームが実行中に終了する可能性がある場合は、プログラムが使用する前にその記述子を確認し、そのストリームで発生したすべてのI / Oイベントを処理していることを確認する必要があります(例えば、またはselectここでも役立ちます)。あります。pollgdb

SIGABRT、、、SIGALRMおよびSIGUSR1SIGUSR2基本的にユーザー信号です。あなたがそれを受け取った場合、実際に受け取った可能性があります。

これにより、キャプチャできない可能性があり、SIGHUP残ります。SIGKILL

  • SIGHUPたとえば、端末でプロセスを開始してからプロセスを分離(disownまたは使用)せずにその端末を閉じると、nohupこれが発生する可能性があります。プログラムがターミナルで起動してデーモンとして実行される場合は、二重分岐などを介してプログラムをシェルから切り離すことを忘れないでください。この特定の信号は、プログラムがGUIから起動する可能性がある場合、または起動時に制御端末が「閉じる」可能性がない場合には関連性が低くなります。

  • SIGKILLご存知のように、これは普遍的なシンボルです。これはカーネルが「私に行きなさい!」と言う方法です。そのシグナルを受け取ったら、プログラムがシグナルを処理するのではなく、シグナルの送信に集中する必要があります。

最後に、信号を分析してデバッグツールを使用することが、これらの問題を解決する最も簡単な方法です。プログラムに問題があるときにカーネルがシグナルをトリガーすると、gdb問題を見つけるのに役立ちます。このような場合は、信号を忘れてエラーに関する情報に集中してください。

信号が「外部」から来る場合、送信機を見つけることはおそらく最善の措置です。(本当に見つからない場合これkill(2)システムコールは最後の手段かもしれません)。その後、無視するか(SIG_IGN)を考慮するかを決定できます。自動実行プログラムも良いオプションです。

関連情報