1 はじめに
シグナルの受信処理について、以下のことを確認してみます。
・同じシグナルを複数回受信した場合の挙動
・通常シグナル、リアルタイムシグナルの受信処理の順序
シグナルについて以下の記事も書きました。
シグナルについて - hana_shinのLinux技術ブログ
2 検証環境
AlmaLinux版数は以下のとおりです。
[root@server ~]# cat /etc/redhat-release AlmaLinux release 9.1 (Lime Lynx)
カーネル版数は以下のとおりです。
[root@server ~]# uname -r 5.14.0-162.6.1.el9_1.x86_64
3 テストプログラム
テストプログラムの内容は次のとおりです。
SIGHUP(1)、SIGINT(2)、SIGRTMAX-1(63)、SIGRTMAX(64)の各シグナルについて、シグナルハンドラを登録し、それらシグナルを受信した際にはシグナル番号を表示します。シグナルハンドラでは、fprintf関数やprintf関数ではなく、シグナルセーフなwriteシステムコールを使ってメッセージを出力します。また、main関数ではfprintfの出力先にstderrを指定しています。これは、メッセージ出力をバッファリングせず、即座に端末に出力できるようにするためです。
[root@server tp]# cat signal.c #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <string.h> void sig_int(int sig) { char msg[100]; snprintf(msg, sizeof(msg), "Signal number:%d\n", sig); write(STDERR_FILENO, msg, strlen(msg)); } int main() { struct sigaction sa[4]; int signals[] = {1, 11, 63, 64}; for (int i = 0; i < 4; ++i) { sa[i].sa_handler = sig_int; sigemptyset(&sa[i].sa_mask); sa[i].sa_flags = 0; sigaction(signals[i], &sa[i], NULL); } fprintf(stderr, "PID=%d\n", getpid()); while(1) { sleep(600); } }
テストプログラムをコンパイルします。
[root@server tp]# gcc -Wall -o signal signal.c
4 同じシグナルを複数回受信した場合について
4.1 通常シグナルを複数回受信した場合
テストプログラムを実行します。
[root@server tp]# ./signal PID=1189
Ctrl+zを押下して、signalプロセスを停止状態にします。なお、SIGSTOPシグナルをsignalプロセスに送信しても同じ状態になります。
[root@server tp]# ./signal PID=1189 ^Z [1]+ 停止 ./signal
psコマンドを使用してsignalプロセスの状態を確認すると、停止状態(STATがT)であることがわかります。
[root@server ~]# ps -C signal s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1189 0000000000000000 0000000000000000 0000000000000000 c000000000000401 T pts/1 0:00 ./signal
signalプロセスにSIGHUPシグナルを3つ送信します。
[root@server ~]# kill -SIGHUP 1189 [root@server ~]# kill -SIGHUP 1189 [root@server ~]# kill -SIGHUP 1189
psコマンドを実行して、signalプロセスの状態を確認します。PENDINGが0000000000000001であることがわかります。
[root@server ~]# ps -C signal s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1189 0000000000000001 0000000000000000 0000000000000000 c000000000000401 T pts/1 0:00 ./signal
シグナルについて - hana_shinのLinux技術ブログに記載したプログラム(signal.py)を実行すると、SIGHUPシグナルが保留されていることがわかります。
[root@server ~]# ./signal.py Please enter a hexadecimal number:0000000000000001 Active signals: SIGHUP(1)
fgコマンドを実行して、signalプロセスを再開します。signalプロセスにSIGHUPシグナルを3つ送信したのですが、シグナルハンドラが1回しか実行されていないので、処理されシグナルは1回だけであることがわかります。
[root@server tp]# fg ./signal Signal number:1
psコマンドを使用してsignalプロセスの状態を確認すると、PENDINGが0000000000000000であることがわかります。
[root@server ~]# ps -C signal s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1189 0000000000000000 0000000000000000 0000000000000000 c000000000000401 S+ pts/0 0:00 ./signal
テストCtrl+cを押下して、テストプログラムを終了します。
[root@server tp]# fg ./signal Signal number:1 ^C
4.2 リアルタイムシグナルを複数回受信した場合
テストプログラムを実行します。
[root@server tp]# ./signal PID=1230
psコマンドを実行して、プロセスの状態を確認します。
[root@server ~]# ps -C signal s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1230 0000000000000000 0000000000000000 0000000000000000 c000000000000401 S+ pts/1 0:00 ./signal
Ctrl+zキーを押下して、signalプロセスを停止状態にします。
[root@server tp]# ./signal PID=1230 ^Z [1]+ 停止 ./signal
psコマンドを使用してsignalプロセスの状態を確認すると、停止状態(STATがT)であることがわかります。
[root@server ~]# ps -C signal s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1230 0000000000000000 0000000000000000 0000000000000000 c000000000000401 T pts/1 0:00 ./signal
signalプロセスにSIGRTMAXシグナルを3つ送信します。
[root@server ~]# kill -SIGRTMAX 1230 [root@server ~]# kill -SIGRTMAX 1230 [root@server ~]# kill -SIGRTMAX 1230
psコマンドを実行して、signalプロセスの状態を確認します。PENDINGが8000000000000000であることがわかります。
[root@server ~]# ps -C signal s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1230 8000000000000000 0000000000000000 0000000000000000 c000000000000401 T pts/1 0:00 ./signal
シグナルについて - hana_shinのLinux技術ブログに記載したプログラムを実行すると、SIGRTMAXシグナルが保留されていることがわかります。
[root@server ~]# ./signal.py Please enter a hexadecimal number:8000000000000000 Active signals: SIGRTMAX(64)
fgコマンドを実行して、signal プロセスを再開します。シグナルハンドラが3回実行されたため、処理されたシグナルは3回であることがわかります。通常のシグナルとは異なり、リアルタイムシグナルは受信したシグナルの回数を実行することができます。
[root@server tp]# fg ./signal Signal number:64 Signal number:64 Signal number:64
signalプロセスが再開して、保留中のシグナルを処理したので、PENDINGが0になったことがわかります。
[root@server ~]# ps -C signal s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1230 0000000000000000 0000000000000000 0000000000000000 c000000000000401 S+ pts/1 0:00 ./signal
5 通常シグナルとリアルタイムシグナルの優先度について
テストプログラムを実行します。
[root@server tp]# ./signal PID=1321
Ctrl+zを押下して、signalプロセスを停止状態にします。
[root@server tp]# ./signal PID=1321 ^Z [1]+ 停止 ./signal
signalプロセスにSIGHUP, SIGSEGV, SIGRTMAX-1, SIGRTMAX を送信します。SIGHUP, SIGSEGVは通常シグナルです。SIGRTMAX-1, SIGRTMAXはリアルタイムシグナルです。
[root@server ~]# kill -SIGHUP 1321 [root@server ~]# kill -SIGSEGV 1321 [root@server ~]# kill -SIGRTMAX-1 1321 [root@server ~]# kill -SIGRTMAX 1321
psコマンドを実行して、signalプロセスの状態を確認します。PENDINGがc000000000000401であることがわかります。
[root@server ~]# ps -C signal s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1321 c000000000000401 0000000000000000 0000000000000000 c000000000000401 T pts/1 0:00 ./signal
signal.pyを実行すると、SIGHUP, SIGSEGV, SIGRTMAX-1, SIGRTMAXが保留されていることがわかります。
[root@server ~]# ./signal.py Please enter a hexadecimal number:c000000000000401 Active signals: SIGHUP(1), SIGSEGV(11), SIGRTMAX-1(63), SIGRTMAX(64)
fgコマンドを実行して、signal プロセスを再開します。リアルタイムシグナル、通常シグナルの順でシグナルが処理されていることがわかります。また、リアルタイムシグナルは番号の大きいものから、通常シグナルは番号の小さいものから処理されていることがわかります。
[root@server tp]# fg ./signal Signal number:64 Signal number:63 Signal number:1 Signal number:11
6 まとめ
項目 | 説明 |
---|---|
通常シグナルとリアルタイムシグナルの優先度 | リアルタイムシグナルが通常シグナルより優先して処理されます |
リアルタイムシグナル同士の優先度 | 番号の大きいリアルタイムシグナルが優先して処理されます |
通常シグナル同士の優先度 | 番号の小さい通常シグナルが優先して処理されます |
同じシグナルの実行回数 | 通常シグナルの場合、同じシグナルをN回受信しても処理するのは1回です。リアルタイムシグナルの場合、同じシグナルをN回受信したら、N回受信処理をします |
Y 参考図書
TECHNICAL MASTER はじめてのAlmaLinux 9 & Rocky Linux 9 Linuxサーバエンジニア入門編
Z 参考情報
私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ