ソフトな忘却力(22) シグナル、無視するにはsigprocmask()使う方が良いのね

Joseph Halfmoon

シリーズ3か月近く間が空きました。気を許すと練習頻度を忘却速度が上回ります。練習再開、テーマは「シグナル」です。マイコンの場合のハードウエア割り込みのようなアカラサマなものではなく、Linuxの管理下にある「ソフトウエア割り込み」的なやつです。今回はシグナルを無視するやり方を練習。

※ソフトな忘却力 投稿順 index はこちら

※実機確認に使用したのは、Raspberry Pi 4 model B機(Arm Cortex-A72)です。Raspberry Pi OS<32bit版、Linux>です。OSバージョンが以下に。多分、大抵のLinuxで同じように走るんじゃないかと思いますが未確認デス。version

以前は、Raspbianと呼んでいたのに、最近公式では Raspberry Pi OSと呼んでいますな。でも、こうして本人?に聞くと Raspbianと名乗ると。。。

シグナル

シグナル、実行中のプログラムをCTRL-Cして止めるとか、暴走しているプログラムをSIGKILL送って止めるとか、時々お世話になるアイツです。

今回はシグナルを無視する技、を練習します。目標としては、キーボードからCTRL-Cで発生するSIGINTを無視するように設定しておいて、「待ち」に入り、CTRL-Cの連打にもかかわらず戻ってこない、でも、他のキッカケでちゃんとプログラム終了する、ということにいたしました。

朧気な記憶によると、Unix()には signal()という関数あり、こいつでシグナルのハンドラを設定できた筈。そして、ハンドラの代わりに SIG_IGN を渡せば、該当シグナルは無視される(OSは該当のシグナルを対象のプロセスに配送しなくなる)筈。以下のMan page(日本語)を参照させていただきました。

SIGNAL

しかし、ということで1か所引用させていただきます。

signal() の動作は UNIX のバージョンにより異なる。 また、歴史的に見て Linux のバージョンによっても異なっている。 このシステムコールの使用は避け、 代わりに sigaction(2) を使用すること。

あれま、signal()は使わないことになっていたのね。しかし、別にシグナルのハンドラを設定したいわけでないので、sigaction()する必要も無さそうです。単にシグナルを無視したりするだけであれば、以下が。

SIGPROCMASK

上記は呼び出したスレッドのシグナルマスクの取得/変更を行うための関数みたいです。

実験用のコード

上記のsigprocmask()関数を使って、SIGINTを無視するだけのプログラムを書いてみました。こんな感じ。

// sigintBLK.c
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

int main(void)
{
    sigset_t newset;

    sigemptyset(&newset);
    sigaddset(&newset, SIGINT);
    if (sigprocmask(SIG_BLOCK, &newset, NULL) != 0) {
        perror("ERROR: sigprocmask.");
    } else {
        printf("MASK SIGINT, use CTRL-\\ for exit.\n");
        pause();
        printf("RETURN FROM pause()\n");
    }

    return 0;
}

なお、pause()関数のMan Pageが以下に。

PAUSE

上記は、「シグナルが配送されるまでスリープ」する関数です。今回 SIGINTは「無視」しているのでCTRL-Cしても反応しない筈ですが、他のシグナルを与えれば反応して戻ってくる、という期待。

ビルドは以下で。

$ gcc -g -O0 -Wall sigintBLK.c
実機確認

生成された a.out を走らせると以下のような感じです。

Result

お約束どおり CTRL-C(SIGINT) を連打しましたが、^Cと画面に表示されるばかりで戻ってきません(マスクしないと pause()はCTRL-Cで戻ってきます。)CTRL-¥(日本語キーボードでは円マークだけれど、バックスラッシ)を打てば、これは SIGQUIT という別なシグナルになるので受付られます。

ちゃんと終わって戻ってきました。とりあえず、シグナルの無視はできた、と。小さな一歩だな。

ソフトな忘却力(21) gcc、デフォルト設定でのNaN、INF、デノーマル数の挙動 へ戻る

ソフトな忘却力(23) time_t型、64bit OS上なら64bitになっていたのね へ進む