Linux Signalの例
信号は、システムがいくつかの条件に応答して生成したイベントであり、そのメッセージを受信したプロセスは、対応する処理を行う.通常、メッセージは、セグメントエラー(
信号定義は
信号は、
プロトタイプ:
ここで、
また、 は無視する. を復元する.
プロトタイプ:
ここで、
を選択します.
名前
説明
void(*) (int)
sa_handler
処理関数ポインタ、signal関数の
sigset_t
sa_mask
信号シールドワードとは、現在ブロックされている信号のセットを指し、現在のプロセスで受信できない
int
sa_flags
[動作を処理](Processing Behavior)モディファイヤで、どの処理関数が有効かを指定します.詳細は以下を参照してください.
void(*) (int, siginfo_t *, void *)
sa_sigaction
関数ポインタの処理、saのみflags == SA_SIGINFO時有効
ここで、 SA_NOCLDSTOPサブプロセス停止時に は発生しない. SA_RESETHANDは、信号の処理関数を処理関数の入口で にリセットする. SA_RESTARTは、 を与えるのではなく、中断可能な関数を再起動する. SA_SIGINFOは、 を用いる SA_NODEFERは、信号をキャプチャする際に、信号マスクワード に追加しない.
簡単なコードの例は次のとおりです.
このような状況を考慮すると、
シールドワードは関数を使用します. SIG_BLOCKプロセスのマスクワードセットは、当期のマスクワードセットと が含まれる. SIG_UNBLOCKプロセスのシールドワードセットは、当期のシールドワードセットと が含まれる. SIG_SETMASKプロセスのマスクワードセットは に設定.
簡単な設定手順は次のとおりです.
信号は、
プロトタイプ:=0信号は、送信者が存在するグループに送信される全プロセス に送信される.=1の信号は、すべてのプロセス に送信される.より小さい信号は、プロセスグループ に送信.
プロトタイプ:
簡単なコードの例は次のとおりです.
プロトタイプ:
信号処理関数は繰り返し呼び出されるので、処理ロジックに注意して再入力可能であることを保存する必要があります.
また、本明細書のコードはsignalにあり、この
SIGSEGV
)のようなエラーによって生成される.しかし、メッセージは、あるプロセスによって別のプロセスに送信されるプロセス間通信の1つの方法としてもよい.信号定義は
signal.h
ファイルにあり、SIG
を先頭とし、kill -l
コマンドで参照できます.詳細はman 7 signalを参照してください.しんごうしょり
信号は、
signal
およびsigaction
の関数によって登録処理することができ、signal
の関数は、struct sigaction
のうちsa_handler
の便利な実装である.Signal関数
プロトタイプ:
void (*signal(int sig, void (*func)(int)))(int);
ここで、
sig
はキャプチャが必要なsignal number
であり、後者は信号をキャプチャした処理関数ポインタであるため、処理関数のプロトタイプはvoid func(int)
でなければならない.簡単なコード例は以下の通りである.#include
#include
#include
static void
handler(int sig)
{
printf("Recieved signal: %d
", sig);
}
int
main(int argc, char *argv[])
{
signal(SIGINT, handler);
printf("Caught SIGINT, input 'quit' to exit...
");
// wait signal caught
char buf[1024] = {0};
while (1) {
printf("Please input: ");
scanf("%s", buf);
if (strcmp(buf, "quit") == 0) {
break;
}
}
printf("Exit...
");
return 0;
}
また、
api
には、以下の2つの特殊なhandler
も提供されている.SIG_IGN
この信号SIG_DFL
この信号のデフォルト動作Sigaction関数
プロトタイプ:
int sigaction(int sig, const struct sigaction *restrict act,
struct sigaction *restrict oact);
ここで、
sig
はsignal number
であり、act
は信号の処理動作を指定し、oact
がNULL
でなければ信号の前の処理動作を返す.struct sigaction
の主要メンバーは次のとおりです.を選択します.
名前
説明
void(*) (int)
sa_handler
処理関数ポインタ、signal関数の
func
パラメータsigset_t
sa_mask
信号シールドワードとは、現在ブロックされている信号のセットを指し、現在のプロセスで受信できない
int
sa_flags
[動作を処理](Processing Behavior)モディファイヤで、どの処理関数が有効かを指定します.詳細は以下を参照してください.
void(*) (int, siginfo_t *, void *)
sa_sigaction
関数ポインタの処理、saのみflags == SA_SIGINFO時有効
ここで、
sa_flags
は主に以下の値に設定できます.SIGCHLD
信号SIG_DFL
EINTR
エラーsa_sigaction
を信号とする処理関数簡単なコードの例は次のとおりです.
#include
#include
#include
#define SIG SIGINT
static void
sig_handler(int sig, siginfo_t *si, void *data)
{
printf("Caught signal: %d
", sig);
printf("Sender pid: %d
", si->si_pid);
printf("Sender uid: %d
", si->si_uid);
}
static int
sig_caught(int sig)
{
printf("Start caught signal: %d
", sig);
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = sig_handler;
sigemptyset(&sa.sa_mask);
int ret = sigaction(sig, &sa, NULL);
if (ret == -1) {
printf("Failed to caught signal: %d
", sig);
return -1;
}
return 0;
}
int
main(int argc, char *argv[])
{
if (sig_caught(SIG) == -1) {
return -1;
}
printf("Caught signal(%d), input 'quit' to exit...
", SIG);
char buf[1024] = {0};
while(1) {
printf("Please input: ");
scanf("%s", buf);
if (strcmp(buf, "quit") == 0) {
break;
}
}
printf("Exit...
");
return 0;
}
しんごうしゃへいご
このような状況を考慮すると、
signal()/sigaction()
が戻る前にプロセスはすでに処理が必要な信号を受信し、このときプロセスはデフォルトの動作で処理され、これは明らかに私たちの期待に合わない.この場合、信号マスクが必要となり、プロセス起動時に処理が必要な信号を加えたマスクのうち、signal()/sigaction()
が戻ってからマスクを解除し、マスクを解除すると少なくとも受信した処理対象信号をプロセスに送信する.シールドワードは関数を使用します.
int sigemptyset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigprocmask(int how, const sigset_t *restrict set,
sigset_t *restrict oset);
sigprocmask
のうちset
は設置が必要なシールドワードセットであり、oset
は以前のシールドワードセットであり、how
はset
がどのように有効になるかを制御しており、以下の値に設定することができる.set
との並列セットとなり、set
にはマスクが必要な信号セットset
の補完セットとの交差であり、set
には、シールドを解除する必要がある信号セットset
の値簡単な設定手順は次のとおりです.
int
sig_block(int sig, int how)
{
sigset_t mask;
sigemptyset(&mask)
sigaddset(&mask, sig);
sigprocmask(how, &mask, NULL);
}
しんごうそうしん
信号は、
kill
関数によって指定されたプロセスに送信されてもよいし、raise
またはalarm
関数によって現在実行されているスレッドまたはプロセスに送信されてもよい.以下、これらの関数をそれぞれ説明する.kill
プロトタイプ:
int kill(pid_t pid, int sig);
kill
関数は、指定された信号を指定プロセスに送信し、0の場合、エラーチェックが実行され、信号は送信されず、pid
の有効性をチェックするために使用することができる.pid
が0より大きい場合、信号はこのプロセスに送信され、pid
が0以下の場合、以下のようになる.pid
の絶対値である全グループ内のプロセスalarm
プロトタイプ:
unsigned alarm(unsigned seconds);
alarm
関数は、指定されたseconds
の後にSIGALRM
信号を送信し、seconds
が0の場合、前のタイマ要求をキャンセルする.0でない場合は、以前のリクエストをキャンセルし、seconds
に再設定します.終了を待つ前に他のイベントが発生した場合、タイマリクエストもキャンセルされます.簡単なコードの例は次のとおりです.
#include
#include
#include
static void
handler(int sig)
{
printf("alarm arrived: %d
", sig);
}
int
main(int argc, char *argv[])
{
signal(SIGALRM, handler);
alarm(2);
sleep(2);
printf("alarm 5s over
");
alarm(10);
sleep(1);
unsigned int remaining = alarm(3);
printf("alarm 10s remain: %u, reset to 3
", remaining);
sleep(3);
printf("alarm 3s over
");
alarm(20);
sleep(3);
remaining = alarm(0);
printf("cancel alarm 20s, remian: %u, exit...
", remaining);
}
raise
プロトタイプ:
int raise(int sig);
raise
関数は、現在実行されているスレッドまたはプロセスに信号を送信し、信号処理関数が呼び出された場合、raise
関数は、信号処理関数呼び出しが終了するまで待機する.締めくくり
信号処理関数は繰り返し呼び出されるので、処理ロジックに注意して再入力可能であることを保存する必要があります.
また、本明細書のコードはsignalにあり、この
repo
には他の例もあり、興味のあるものは見てみましょう.ふろく
しんごうひょう
/* ISO C99 signals. */
#define SIGINT 2 /* Interactive attention signal. */
#define SIGILL 4 /* Illegal instruction. */
#define SIGABRT 6 /* Abnormal termination. */
#define SIGFPE 8 /* Erroneous arithmetic operation. */
#define SIGSEGV 11 /* Invalid access to storage. */
#define SIGTERM 15 /* Termination request. */
/* Historical signals specified by POSIX. */
#define SIGHUP 1 /* Hangup. */
#define SIGQUIT 3 /* Quit. */
#define SIGTRAP 5 /* Trace/breakpoint trap. */
#define SIGKILL 9 /* Killed. */
#define SIGBUS 10 /* Bus error. */
#define SIGSYS 12 /* Bad system call. */
#define SIGPIPE 13 /* Broken pipe. */
#define SIGALRM 14 /* Alarm clock. */
/* New(er) POSIX signals (1003.1-2008, 1003.1-2013). */
#define SIGURG 16 /* Urgent data is available at a socket. */
#define SIGSTOP 17 /* Stop, unblockable. */
#define SIGTSTP 18 /* Keyboard stop. */
#define SIGCONT 19 /* Continue. */
#define SIGCHLD 20 /* Child terminated or stopped. */
#define SIGTTIN 21 /* Background read from control terminal. */
#define SIGTTOU 22 /* Background write to control terminal. */
#define SIGPOLL 23 /* Pollable event occurred (System V). */
#define SIGXCPU 24 /* CPU time limit exceeded. */
#define SIGXFSZ 25 /* File size limit exceeded. */
#define SIGVTALRM 26 /* Virtual timer expired. */
#define SIGPROF 27 /* Profiling timer expired. */
#define SIGUSR1 30 /* User-defined signal 1. */
#define SIGUSR2 31 /* User-defined signal 2. */
/* Nonstandard signals found in all modern POSIX systems
(including both BSD and Linux). */
#define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */
/* Archaic names for compatibility. */
#define SIGIO SIGPOLL /* I/O now possible (4.2 BSD). */
#define SIGIOT SIGABRT /* IOT instruction, abort() on a PDP-11. */
#define SIGCLD SIGCHLD /* Old System V name */
/* Not all systems support real-time signals. bits/signum.h indicates
that they are supported by overriding __SIGRTMAX to a value greater
than __SIGRTMIN. These constants give the kernel-level hard limits,
but some real-time signals may be used internally by glibc. Do not
use these constants in application code; use SIGRTMIN and SIGRTMAX
(defined in signal.h) instead. */
#define __SIGRTMIN 32
#define __SIGRTMAX __SIGRTMIN
/* Biggest signal number + 1 (including real-time signals). */
#define _NSIG (__SIGRTMAX + 1)