- 1 はじめに
- 2 検証環境
- 3 シグナル一覧を表示する方法
- 4 シグナルを送信する方法
- 5 シグナルの状態を表示する方法
- 6 CAUGHTの確認方法
- 7 PENDINGの確認方法
- 8 IGNOREDの確認方法
- 9 BLOCKEDの確認方法
- X シグナル名とシグナル番号を表示するプログラム
- Y 参考図書
- Z 参考情報
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 シグナル一覧を表示する方法
killコマンドを実行すると、シグナルの一覧を表示することができます。通常シグナルは1~32までの範囲で、リアルタイムシグナルは33~64までの範囲にあります。
[root@server ~]# kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX
4 シグナルを送信する方法
killコマンドを実行すると、プロセスにシグナルを送信することができます。ここでは、sleepプロセスにSIGKILLシグナルを送信してみます。まず、sleepコマンドを実行します。sleepコマンドを実行すると、sleepプロセスが起動され、その後600秒スリープします。
[root@server ~]# sleep 600
psコマンドを実行して、sleepプロセスのPIDを確認します。sleepプロセスのPIDは19876であることがわかります。なお、psコマンドの使い方は、psコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# ps -C sleep PID TTY TIME CMD 19867 pts/2 00:00:00 sleep
4.1 シグナル名を指定する方法
シグナル名を指定してkillコマンドを実行します。
[root@server ~]# kill -SIGKILL 19867
sleepプロセスがSIGKILLシグナルを受信すると、強制終了することがわかります。
[root@server ~]# sleep 600 強制終了
4.2 シグナル番号を指定する方法
シグナル番号を指定してkillコマンドを実行します。
[root@server ~]# kill -9 1188
sleepプロセスがSIGKILLシグナルを受信すると、強制終了することがわかります。
[root@server ~]# sleep 600 強制終了
5 シグナルの状態を表示する方法
psコマンドにsオプションを指定すると、シグナルの各種状態(PENDING、BLOCKED、IGNORED、CAUGHT)を表示することができます。ここでは、これらの各種状態をシグナル情報と呼ぶことにします。シグナル情報は64ビットのデータです。通常シグナルには32ビットが割り当てられており、リアルタイムシグナルにも32ビットが割り当てられています。
[root@server ~]# ps s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 672 0000000000000000 0000000000000000 0000000000000006 0000000000000000 Ss+ tty1 0:00 /sbin/agetty -o -p 0 1124 0000000000000000 0000000000010000 0000000000384004 000000004b813efb Ss pts/0 0:00 -bash 0 1195 0000000000000000 0000000000000000 0000000000384004 000000004b813efb Ss+ pts/1 0:00 -bash 0 19660 0000000000000000 0000000000010000 0000000000384004 000000004b813efb Ss pts/2 0:00 -bash 0 19908 0000000000000000 0000000000000000 0000000000000000 0000000000000000 S+ pts/2 0:00 sleep 600 0 19915 0000000000000000 0000000000000000 0000000000000000 0000000073d1fef9 R+ pts/0 0:00 ps s
シグナル情報の意味は以下のとおりです。
シグナル情報 | 意味 |
---|---|
PENDING | プロセスが受信したがまだ処理していないシグナルを示します |
BLOCKED | プロセスが特定のシグナルを受信しないように一時的にシグナルの処理をブロックするシグナルを示します。ブロックを解除するとシグナルを処理します |
IGNORED | プロセスが特定のシグナルを受信しても無視するシグナルを示します |
CAUGHT | シグナルハンドラを登録しているシグナルを示します |
PIDを指定すると、特定プロセスのシグナル情報を表示することができます。ここでは、systemd(PID=1)のシグナル情報を表示してみます。
[root@server ~]# ps s -p 1 UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1 0000000000000000 7fe3c0fe28014a03 0000000000001000 00000001000004ec Ss ? 0:05 /usr/lib/systemd/s
次のようにフォーマットを明に指定しても、プロセスのシグナル情報を表示することができます。
[root@server ~]# ps -p 1 -o comm,pid,sig,sigmask,sigignore,sigcatch COMMAND PID PENDING BLOCKED IGNORED CAUGHT systemd 1 0000000000000000 7fe3c0fe28014a03 0000000000001000 00000001000004ec
-Cオプションでプロセス名を指定すると、指定したプロセスのシグナル情報を表示することができます。chronydプロセスのシグナル情報を表示してみます。
[root@server ~]# ps -C chronyd -o comm,pid,sig,sigmask,sigignore,sigcatch COMMAND PID PENDING BLOCKED IGNORED CAUGHT chronyd 656 0000000000000000 0000000000000000 0000000000001000 0000000100004007
記事末尾のサンプルプログラム(signal.py)を使用してIGNOREDのシグナル名を確認すると、SIGPIPEが無視されていることがわかります。
[root@server ~]# ./signal.py Please enter a hexadecimal number:0000000000001000 Active signals: SIGPIPE(13)
次に、chronydプロセスがSIGPIPEシグナルを無視するかどうかを確認するため、chronydプロセスにSIGPIPEシグナルを送信してみます。通常、SIGPIPEを受信するとプロセスは終了しますが、chronydプロセスはSIGPIPEシグナルを無視する設定になっているため、SIGPIPEシグナルを受信してもchronydプロセスは終了しません。
[root@server ~]# kill -SIGPIPE 656
chronydプロセスの状態を確認します。chronydプロセスのPIDは656のままで、chronydプロセスが終了していないことがわかります。
[root@server ~]# ps -C chronyd -o comm,pid,sig,sigmask,sigignore,sigcatch COMMAND PID PENDING BLOCKED IGNORED CAUGHT chronyd 656 0000000000000000 0000000000000000 0000000000001000 0000000100004007
6 CAUGHTの確認方法
6.1テストプログラムの作成
CAUGHTを確認するためのテストプログラムを作成します。SIGHUP(1)、SIGINT(2)、SIGRTMAX-1(63)、SIGRTMAX(64)の各シグナルについて、シグナルハンドラを登録し、それらシグナルを受信した際にはシグナル番号を表示します。シグナルハンドラでは、fprintf関数やprintf関数ではなく、シグナルセーフなwriteシステムコールを使ってメッセージを出力します。また、main関数ではfprintfの出力先にstderrを指定しています。これは、メッセージ出力をバッファリングせず、即座に端末に出力できるようにするためです。
[root@server ~]# 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, 2, 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 ~]# gcc -Wall -o signal signal.c
6.2 確認結果
テストプログラムを実行します。
[root@server ~]# ./signal PID=1421
psコマンドを実行してシグナル情報を確認すると、CAUGHTがc000000000000003であることがわかります。
[root@server ~]# ps -C signal s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1421 0000000000000000 0000000000000000 0000000000000000 c000000000000003 S+ pts/1 0:00 ./signal
signal.pyを実行すると、CAUGHTのc000000000000003は、テストプログラムで定義した4つのシグナルを補足することを示していることがわかります。
[root@server ~]# ./signal.py Please enter a hexadecimal number:c000000000000003 Active signals: SIGHUP(1), SIGINT(2), SIGRTMAX-1(63), SIGRTMAX(64)
7 PENDINGの確認方法
6章と同じテストプログラムを実行します。signalプロセスのPIDが1207であることがわかります。
[root@server ~]# ./signal PID=1207
Ctrl+zキーを押下して、signalプロセスを停止状態にします。なお、SIGSTOPシグナルをsignalプロセスに送信しても同じ状態になります。
[root@server ~]# ./signal PID=1207 ^Z [1]+ 停止 ./signal
psコマンドを使用してsignalプロセスの状態を確認すると、停止状態(STATがT)であることがわかります。
[root@server ~]# ps -C signal s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1207 0000000000000000 0000000000000000 0000000000000000 c000000000000003 S+ pts/1 0:00 ./signal
signalプロセスにSIGHUP(1)シグナルを送信します。
[root@server ~]# kill -1 1207
psコマンドを実行してシグナル情報を確認すると、PENDINGが0000000000000001になったことがわかります。
[root@server ~]# ps -C signal s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1207 0000000000000001 0000000000000000 0000000000000000 c000000000000003 T pts/1 0:00 ./signal
signal.pyを実行すると、SIGHUPシグナルが保留されていることがわかります。これは、シグナルを受信するプロセスが停止状態になっているため、SIGHUPシグナルを受信しても処理できずに保留しているからです。
[root@server ~]# ./signal.py Please enter a hexadecimal number:0000000000000001 Active signals: SIGHUP(1)
次に、signalプロセスにSIGINT(2)、SIGRTMAX-1(63)、SIGRTMAX(64)を送信します。
[root@server ~]# kill -2 1207 [root@server ~]# kill -63 1207 [root@server ~]# kill -64 1207
psコマンドを実行してシグナル情報を確認すると、PENDINGがc000000000000003になっていることがわかります。
[root@server ~]# ps -C signal s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1207 c000000000000003 0000000000000000 0000000000000000 c000000000000003 T pts/1 0:00 ./signal
signal.pyを使ってPENDINGのシグナルを確認すると、SIGHUP(1)、SIGINT(2)、SIGRTMAX-1(63)、SIGRTMAX(64)が保留中であることがわかります。
[root@server ~]# ./signal.py Please enter a hexadecimal number:c000000000000003 Active signals: SIGHUP(1), SIGINT(2), SIGRTMAX-1(63), SIGRTMAX(64)
fgコマンドを実行して、signalプロセスを停止状態からスリープ状態に戻します。
[root@server ~]# fg ./signal Signal number:64 Signal number:63 Signal number:2 Signal number:1
psコマンドを実行してシグナル情報を確認します。signalプロセスが起床して、保留中のシグナルを処理したので、PENDINGが0になったことがわかります。
[root@server ~]# ps -C signal s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1207 0000000000000000 0000000000000000 0000000000000000 c000000000000003 S+ pts/1 0:00 ./signal
8 IGNOREDの確認方法
8.1テストプログラムの作成
IGNOREDを確認するためのテストプログラムを作成します。実行開始から30秒間は、SIGHUP(1)、SIGINT(2)、SIGRTMAX-1(63)、SIGRTMAX(64)を受信しても無視します。30秒経過すると、無視していたシグナルを実行します。
[root@server ~]# cat signal1.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, 2, 63, 64}; int block_time = 30; for (int i = 0; i < 4; ++i) { sa[i].sa_handler = SIG_IGN; sigemptyset(&sa[i].sa_mask); sa[i].sa_flags = 0; sigaction(signals[i], &sa[i], NULL); } fprintf(stderr, "PID=%d\n", getpid()); sleep(block_time); for (int i = 0; i < 4; ++i) { sa[i].sa_handler = sig_int; sigaction(signals[i], &sa[i], NULL); } fprintf(stderr, "Signals unblocked.\n"); while(1) { sleep(600); } return 0; }
テストプログラムをコンパイルします。
[root@server ~]# gcc -Wall -o signal1 signal1.c
8.2 確認結果
テストプログラムを実行します。
[root@server ~]# ./signal1 PID=1318
プロセスの状態を確認すると、IGNOREDがc000000000000003になっていることがわかります。
[root@server ~]# ps -C signal1 s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1318 0000000000000000 0000000000000000 c000000000000003 0000000000000000 S+ pts/1 0:00 ./signal1
signalプロセスにSIGHUP(1), SIGINT(2), SIGRTMAX-1(63), SIGRTMAX(64)を送信します。
[root@server ~]# kill -1 1318 [root@server ~]# kill -2 1318 [root@server ~]# kill -63 1318 [root@server ~]# kill -64 1318
シグナルを受信してもシグナル番号が表示されないことから、シグナルが無視されていることがわかります。
[root@server ~]# ./signal1 PID=1318
30秒経過したあと、プロセスの状態を確認するとIGNOREDが0000000000000000になっていることがわかります。
[root@server ~]# ps -C signal1 s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1318 0000000000000000 0000000000000000 0000000000000000 c000000000000003 S+ pts/1 0:00 ./signal1
signalプロセスにSIGHUP(1), SIGINT(2), SIGRTMAX-1(63), SIGRTMAX(64)を送信します。
[root@server ~]# kill -1 1318 [root@server ~]# kill -2 1318 [root@server ~]# kill -63 1318 [root@server ~]# kill -64 1318
シグナルを受信してシグナルハンドラが実行されたため、シグナル番号が表示されていることがわかります。
[root@server ~]# ./signal1 PID=1318 Signals unblocked. Signal number:1 Signal number:2 Signal number:63 Signal number:64
9 BLOCKEDの確認方法
9.1テストプログラムの作成
BLOCKEDを確認するためのテストプログラムを作成します。テストプログラムを実行すると30秒間シグナルの受信処理をブロックします。30秒経過するとブロックを解除してシグナルの受信処理を実行します。
[root@server ~]# cat signal2.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, 2, 63, 64}; int block_time = 30; sigset_t set; 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()); sigemptyset(&set); for (int i = 0; i < 4; ++i) { sigaddset(&set, signals[i]); } sigprocmask(SIG_BLOCK, &set, NULL); fprintf(stderr, "Signals blocked for %d seconds.\n", block_time); sleep(block_time); sigprocmask(SIG_UNBLOCK, &set, NULL); fprintf(stderr, "Signals unblocked.\n"); while (1) { sleep(600); } return 0; }
テストプログラムをコンパイルします。
[root@server ~]# gcc -Wall -o signal2 signal2.c
9.2 確認結果
テストプログラムを実行します。
[root@server ~]# ./signal2 PID=1383
プロセスの状態を確認すると、BLOCKEDがc000000000000003になっており、SIGHUP(1)、SIGINT(2)、SIGRTMAX-1(63)、SIGRTMAX(64)がブロックされれいることを示しています
[root@server ~]# ps -C signal2 s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1383 0000000000000000 c000000000000003 0000000000000000 c000000000000003 S+ pts/0 0:00 ./signal2
signalプロセスにSIGHUP(1), SIGINT(2), SIGRTMAX-1(63), SIGRTMAX(64)を送信します。
[root@server ~]# kill -1 1383 [root@server ~]# kill -2 1383 [root@server ~]# kill -63 1383 [root@server ~]# kill -64 1383
プロセスの状態を確認すると、PENDINGがc000000000000003になっており、SIGHUP(1)、SIGINT(2)、SIGRTMAX-1(63)、SIGRTMAX(64)が保留中であることを示しています。これは、シグナルの受信処理がブロックされていてシグナルが保留されているからです。
[root@server ~]# ps -C signal2 s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1383 c000000000000003 c000000000000003 0000000000000000 c000000000000003 S+ pts/0 0:00 ./signal2
テストプログラムを実行して30秒経過するとブロックしているシグナルのシグナルハンドラが実行されます。シグナルの処理はリアルタイムシグナルが通常シグナルの処理より優先されます。また、シグナル番号の大きいシグナルから処理されていることがわかります。
[root@server ~]# ./signal2 PID=1383 Signals blocked for 30 seconds. Signal number:64 Signal number:63 Signal number:2 Signal number:1 Signals unblocked.
プロセスの状態を確認すると、BLOCKEDが0000000000000000 になっていることがわかります。これは、30秒経過してブロックしていたシグナルを解除したからです。
[root@server ~]# ps -C signal2 s UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 0 1383 0000000000000000 0000000000000000 0000000000000000 c000000000000003 S+ pts/0 0:00 ./signal2
X シグナル名とシグナル番号を表示するプログラム
以下は、シグナル情報の16進数をシグナル名とシグナル番号で表示するプログラムです。
[root@server ~]# cat signal.py #!/usr/bin/python3 def binary_to_signals(hex_input): signals = [ "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE", "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGIO", "SIGPWR", "SIGSYS", "SIGUNUSED", "SIGUNUSED", "SIGRTMIN", "SIGRTMIN+1", "SIGRTMIN+2", "SIGRTMIN+3", "SIGRTMIN+4", "SIGRTMIN+5", "SIGRTMIN+6", "SIGRTMIN+7", "SIGRTMIN+8", "SIGRTMIN+9", "SIGRTMIN+10", "SIGRTMIN+11", "SIGRTMIN+12", "SIGRTMIN+13", "SIGRTMIN+14", "SIGRTMIN+15", "SIGRTMAX-14", "SIGRTMAX-13", "SIGRTMAX-12", "SIGRTMAX-11", "SIGRTMAX-10", "SIGRTMAX-9", "SIGRTMAX-8", "SIGRTMAX-7", "SIGRTMAX-6", "SIGRTMAX-5", "SIGRTMAX-4", "SIGRTMAX-3", "SIGRTMAX-2", "SIGRTMAX-1", "SIGRTMAX", ] signals_activated = [] binary_str = bin(int(hex_input, 16))[2:] binary_str = binary_str.zfill(64) for i, bit in enumerate(reversed(binary_str)): if bit == "1": if i < len(signals): signal_name = signals[i] signal_number = i + 1 signals_activated.append(f"{signal_name}({signal_number})") return signals_activated if __name__ == "__main__": hex_input = input("Please enter a hexadecimal number:") if not all(ch in "0123456789abcdefABCDEF" for ch in hex_input): print("Input error: Please enter a hexadecimal number.") else: activated_signals = binary_to_signals(hex_input) if not activated_signals: print("There are no active signals:") else: print("Active signals:") for i in range(0, len(activated_signals), 5): signals_line = ", ".join(activated_signals[i:i+5]) print(signals_line)
実行権を付与します。
[root@server ~]# chmod 744 signal.py
Y 参考図書
TECHNICAL MASTER はじめてのAlmaLinux 9 & Rocky Linux 9 Linuxサーバエンジニア入門編
Z 参考情報
私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ