#はじめに
##概要
ユーザの操作によってCプログラムが終了してしまうのを(可能な限り)回避する方法をCソースで解説します。
この記事を参考にすると例えばCプログラムを実行中にCtrl+Cを押下した際でも
終了することなく動作し続けるプログラムが作れます。
##目的
以下の用途に使える(かもしれない)。
- 絶対に途中で止めてはならぬバッチ処理
- プロンプト機能を実装する場合
#仕組み
通常、Terminal上でプログラムが動作している際にCtrl + Cを押下すると、
対象プログラムのプロセスにSIGINTシグナル(プロセスを管理するための信号的なもの)が配送されます。
SIGINTシグナルを受け取ったプログラムはOSによって処理が強制終了されます。
今回はシグナル処理設定をCプログラム上で変更し、
SIGINTシグナルを受け取っても終了しないようにOSにお願いする(無視してもらう)感じで
強制終了を回避します。
#シグナルの種類
シグナルはSIGINTだけではなく様々なシグナルが存在します。
強制終了に関係しそうな一部を以下に示します。
シグナル | 概要 | どうやって配送? |
---|---|---|
SIGINT | キーボードからの割り込み | Ctrl + C 押下 |
SIGQUIT | キーボードによる中止 | Ctrl + ''またはCtrl + '4'押下 |
SIGTSTP | 端末(tty)から入力された一旦停止 | Ctrl + Z押下 |
SIGTERM | 終了 | (コマンド) kill pid |
SIGKILL | 強制終了 | (コマンド) kill -KILL pid |
SIGSTOP | 一時停止 | (コマンド) kill -s SIGSTOP pid |
他にもSIGPWR(電源喪失)などがあったりします。
詳しくはこちらを参考ください。
#シグナル処理の変更(上書き)
(途中)
先ほど挙げたシグナルを受け取った際の動作を無視する事が可能です。
例えばSIGINTを受け取った際の処理を無視するには以下のようになります。
signal()よりもsigaction()を使った方が良いみたいです。参考程度に。。
// Ctrl + C を無視
sig = signal( SIGINT , SIG_IGN );
if( SIG_ERR == sig ){
exit(-1);
}
##強制終了回避(出来るだけ)
signal()またはsigaction()を使用しても、
SIGKILL(強制終了)とSIGSTOP(一時停止)に関しては無視できないみたいです。
とりあえず出来るだけ無視してみたコードは以下になります。
signal()よりもsigaction()を使った方が良いみたいです。参考程度に。。
#define _GNU_SOURCE // sighandler_tを使用する為に定義
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
int main( void ){
sighandler_t sig = 0;
// Ctrl + C を無視
sig = signal( SIGINT , SIG_IGN );
if( SIG_ERR == sig ){
exit(-1);
}
// kill pidを無視
sig = signal( SIGTERM , SIG_IGN );
if( SIG_ERR == sig ){
exit(-1);
}
// Ctrl + '\'を無視
sig = signal( SIGQUIT , SIG_IGN );
if( SIG_ERR == sig ){
exit(-1);
}
// Ctrl + Zを無視
sig = signal( SIGTSTP , SIG_IGN );
if( SIG_ERR == sig ){
exit(-1);
}
while(1){
pause();
}
return 0;
}
別ターミナルからは終了できてしまいますが、
プログラムを起動したターミナル側では動き続けるようになるはずです。
以上です。