Linuxシステムコールの勉強(その4)

Linuxシステムコール

Linuxシステムコール

前回はこちら


今回はシグナルを受け取った際に処理を行うためのSignal Handlerの割り当て方とその特性についてまとめます。


まずSignall Handlerを変更するためのシステムコールはsignal()です。定義はちょっと変わっててこんな感じです。

void (*signal(int signum, void (*handler)(int)))(int);


第一引数signumは変更するsignalの番号を指定します。直接数字を入れてもいいし、signal.hに定義されているSIG???を渡してもOKです。

第二引数*handlerにはシグナルを受け取った際に実行する関数へのポインタを渡します。この関数は以下の形式でなければいけません。

void xxxxx(int signum)


個人的には、これまたWindowsでEvent Handlerを作成する時と同じなので理解しやすいです。


また第二引数としてSIG_DFLSIG_IGNといった記号定数も指定する事が可能です。これらを含めて一度まとめます。

※signal()の第二引数について

種類 説明 主な用途
SIG_DFL 既定の動作をする signal()を使用して変更してしまったSignal Handlerを初期化する
SIG_IGN シグナルを無視する 強制終了したくない場合や一時的にシグナルを受け取りたくない場合に利用する
シグナルハンドラ 任意の処理を実行する シグナルに応じて個別に処理を書き分けたい場合に利用する

さて。
以下のプログラムで簡単に動作を確認してみます。

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

// SIGINT用のSignal Handler //
void sig_int( int sig )
{
    printf("signal %d received\n", sig);

    // SIGINTに対するSignal Handlerを再設定 //
    if (signal(SIGINT, sig_int) == SIG_ERR)
    {
        signal(sig, sig_int);
        exit(1);
    }
}


int main()
{
    int i = 0 ;

    // SIGINTに対するSignal Handlerを設定 //
    if (signal(SIGINT, sig_int) == SIG_ERR)
    {
        perror("signal()");
        return 1;
    }

    while (1)
    {
        printf("%03d : process running....\n", i++);
        sleep(1);
    }

    return 0;
}


ポイントは

    1. signal()を使ってsig_int()をSIGINTに対するSignal Handlerに設定している
    2. sig_int()内でsig_int()をSignal Handlerに再設定している
    3. signal()のエラーチェックにはSIG_ERRという定数が利用可


の2点です。


1.は上で説明したsignal()を利用したHandlerの設定です。
2.はsignal()で設定したSignal Handlerは一度呼び出されると既定の動作に戻るための対応です。
# つまりSignal Handlerが呼び出された後にsignal(sig, SIG_DFL)が呼ばれているのと同じ動作をします

3.はsignal()の定義自体が特殊なため、普通にエラーチェックをすると読みにくいソースになってしまいます。そのため、SIG_ERRという定数が利用出来ます。ちなみにこれを使わないでエラーチェックをするとこんな感じになります。

    // SIGINTに対するSignal Handlerを設定 //
    if (signal(SIGINT, sig_int) == (void(*())(int))-1)
    {
        perror("signal()");
        return 1;
    }


また、2.については特に注意が必要です。特定のシグナルに対して常に同じ動作をさせるためには、設定したHandlerの最後で明示的にHandlerを再設定する必要があるということは忘れないようにしないといけません。


といったところで次回はプロセス間でシグナルを送信する方法をまとめます。


次へ進む