はじめに
課題に使用するシグナル系の関数のmanを個人的に見やすいようにまとめました。
個人的に使用するための要約ですので、正確な情報はmanをご確認ください。
signal
ANSI C シグナル操作
# include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t sighandler);
signal() の動作は UNIX のバージョンにより異なる。 また、歴史的に見て Linux のバージョンによっても異なっている。 このシステムコールの使用は避け、 代わりに sigaction(2) を使用すること。
sigaction
シグナルの動作の確認と変更
# include <signal.h>
int sigaction(
int signum,
const struct sigaction *act,
struct sigaction *oldact
);
sigaction() システムコールは、特定のシグナルを受信した際の プロセスの動作を変更するのに使用される (シグナルの概要については signal(7) を参照)。
signum
SIGKILL と SIGSTOP 以外の有効なシグナルをどれでも指定できる。
act
NULL 以外であれば、シグナル signum の新しい動作 (action) として act が設定される。
oldact
NULL でなければ、今までの動作が oldact に格納される。
返り値
sigaction() 関数は成功すると 0 を返す。
エラーの場合、-1 を返し、 errno にエラーを示す値をセットする。
エラー
EFAULT
act か oldact が指しているメモリーが正しいプロセスのアドレス空間にない。
EINVAL
無効なシグナルが指定された。補足 (catch) したり無視したりできない シグナルである SIGKILL や SIGSTOP に対する動作を変更しようとした場合にも発生する。
sigaction 構造体
以下のように定義される。
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
アーキテクチャーによっては共用体 (union) が用いられており、その場合には sa_handler と sa_sigaction の両方を同時に割り当てることはできない。
sa_restorer はアプリケーションが使用することを意図したフィールドではない (POSIX は sa_restorer フィールドを規定していない)。 このフィールドの詳細な目的については sigreturn(2) に書かれている。
handlerの定義方法
void handler(int sig, siginfo_t *info, void *ucontext) {
... }
sig
ハンドラーの呼び出しを引き起こしたシグナルの番号。
info
siginfo_tへのポインタ。これは、以下で説明するように、信号に関する詳細情報を含む構造体です。
ucontext
通常、ハンドラー関数は3番目の引数を使用しません。
これはucontext_t構造へのポインターであり、void *にキャストされます。
このフィールドが指す構造には、カーネルによってユーザースペーススタックに保存された信号コンテキスト情報が含まれています。
詳細については、sigreturn(2)を参照してください。
ucontext_t構造体の詳細については、getcontext(3)およびsignal(7)を参照してください。
siginfo_t
siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; /* Trap number that caused hardware-generated signal (unused on most architectures) */
pid_t si_pid; /* Sending process ID */
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
union sigval si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count; POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void *si_addr; /* Memory location which caused fault */
long si_band; /* Band event (was int in glibc 2.3.2 and earlier) */
int si_fd; /* File descriptor */
short si_addr_lsb; /* Least significant bit of address (since Linux 2.6.32) */
void *si_lower; /* Lower bound when address violation occurred (since Linux 3.19) */
void *si_upper; /* Upper bound when address violation occurred (since Linux 3.19) */
int si_pkey; /* Protection key on PTE that caused fault (since Linux 4.6) */
void *si_call_addr; /* Address of system call instruction (since Linux 3.5) */
int si_syscall; /* Number of attempted system call (since Linux 3.5) */
unsigned int si_arch; /* Architecture of attempted system call (since Linux 3.5) */
}
kill(2) や sigqueue(3) で送信されたシグナルでは si_pid と si_uid が設定される。
さらに、 sigqueue(3) で送信されたシグナルでは si_int と si_pid にシグナルの送信者により指定された値が設定される。詳細は sigqueue(3) を参照。
sigsetpos
# include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
これらの関数は POSIX シグナル集合(signal set)を操作するため使用する。
sigemptyset()
は set で与えられたシグナル集合を空に初期化し、シグナルが一つも 含まれていない状態にする。
sigfillset()
は set で与えられたシグナル集合が全てのシグナルを含むようにする。
sigaddset()
と sigdelset()
は set に signum シグナルをそれぞれ加えたり、削除したりする。
sigismember()
は signum が set に含まれているかどうかをテストする。
sigset_t型のオブジェクトについて
sigset_t
型のオブジェクトは、関数 sigaddset()
, sigdelset()
, sigismember()
や後述の glibc の追加関数 (sigisemptyset()
, sigandset()
, sigorset()
) に渡す前に、 sigemptyset()
か sigfillset()
を呼び出して初期化しなければならない。
初期化しなかった場合の結果は未定義である。
返り値
sigemptyset()
, sigfillset()
, sigaddset()
, sigdelset()
は成功すれば 0 を、エラーの場合は -1 を返す。
sigismember()
は signum が set のメンバの場合 1 を返し、メンバでない場合 0 を返す。 エラーの場合、-1 を返す。
エラーの場合、 errno にエラーの原因を示す値を設定する。
エラー
EINVAL
signum が有効なシグナルではない。
sleep
sleep - 指定の秒数の間だけ休止する
# include <unistd.h>
unsigned int sleep(unsigned int seconds);
返り値
要求された時間が過ぎた場合はゼロを返す。
呼び出しがシグナルハンドラーに割り込まれた場合は、 休止の残り時間を返す。
usleep
usleep - マイクロ秒単位で実行を延期する
# include <unistd.h>
int usleep(useconds_t usec);
usleep() 関数は (少なくとも) usecマイクロ秒の間、 呼び出し元スレッドの実行を延期する。
システムの動作状況や呼び出しによる時間の消費やシステムタイマーの粒度によって、 停止時間は設定した値よりも少し延ばされるかもしれない。
返り値
usleep() 関数は成功すると 0 を返す。
エラーの場合、 -1 が返され、 errno にエラーの原因を示す値が設定される。
errror
EINTR
シグナルによって中断された。 signal(7) 参照。
EINVAL
usec が 1000000 以上だった。 (これをエラーとみなすシステムのみ)
kill
kill - プロセスにシグナルを送る
# include <sys/types.h>
# include <signal.h>
int kill(pid_t pid, int sig);
pid_tは私の環境では、int型をtypedefしたものだった。
システムコールの kill() は、任意のプロセスグループもしくはプロセスにシグナルを 送るのに使われる。
pid | 動き
- | -
正の値 | シグナル sig が pid で指定された ID を持つプロセスに送られる。
0 | 呼び出し元のプロセスのプロセスグループに属するすべてのプロセスに sig で指定したシグナルが送られる。
-1 | sig で指定したシグナルが、 呼び出し元のプロセスがシグナルを送る許可を持つ全てのプロセスに 送られる。
但し、プロセス番号 1 (init) へはシグナルは送られない。
-1より小さい値 | ID が -pid のプロセスグループに属するすべてのプロセスに sig で指定したシグナルが送られる。
返り値
成功した場合 (少なくとも一つのシグナルが送信された場合)、 0 が返される。エラーの場合 -1 が返され、 errno が適切に設定される。
エラー
EINVAL
無効なシグナルを指定した。
EPERM
呼び出し元のプロセスが、受信するプロセスのいずれに対しても シグナルを送る許可を持っていない。
ESRCH
ターゲットプロセスまたはプロセスグループが存在しない。
既存のプロセスはゾンビである可能性があることに注意してください。ゾンビは、実行を終了したものの、まだ待機(2)されていないプロセスです。
pause
シグナルを待つ
# include <unistd.h>
int pause(void);
pause() は、呼び出したプロセス (またはスレッド) を、そのプロセスを終了させたり、シグナル捕捉関数が起動されるような シグナルが配送されるまで、スリープさせる。
返り値
pause() が返るのは、シグナルを受け取りシグナル捕獲関数から返った場合だけである。
この場合は pause() は -1 を返し、 errno に EINTR
が設定される。
エラー
EINTR
シグナルを受け取り、シグナル捕獲関数から帰ってきた。
参考
Man page of SIGNAL
Man page of SIGACTION
Man page of SIGSETOPS
Man page of KILL
Man page of PAUSE
Man page of SLEEP
Man page of USLEEP