C言語　シグナル系関数まとめ

# はじめに

課題に使用するシグナル系の関数のmanを個人的に見やすいようにまとめました。
個人的に使用するための要約ですので、正確な情報はmanをご確認ください。

## signal

ANSI C シグナル操作  

```c
#include <signal.h>
typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t sighandler); 
```

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

## sigaction

シグナルの動作の確認と変更 

```c
#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 構造体

以下のように定義される。

```c
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の定義方法

```c
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

```c
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

```c
#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 - 指定の秒数の間だけ休止する  

```c
#include <unistd.h>

unsigned int sleep(unsigned int seconds);
```

### 返り値

要求された時間が過ぎた場合はゼロを返す。 
呼び出しがシグナルハンドラーに割り込まれた場合は、 休止の残り時間を返す。  

[Man page of SLEEP](https://linuxjm.osdn.jp/html/LDP_man-pages/man3/sleep.3.html)

## usleep

usleep - マイクロ秒単位で実行を延期する  

```c
#include <unistd.h>

int usleep(useconds_t usec);
```

usleep() 関数は (少なくとも) usecマイクロ秒の間、 呼び出し元スレッドの実行を延期する。 
システムの動作状況や呼び出しによる時間の消費やシステムタイマーの粒度によって、 停止時間は設定した値よりも少し延ばされるかもしれない。  

### 返り値

usleep() 関数は成功すると 0 を返す。
エラーの場合、 -1 が返され、 errno にエラーの原因を示す値が設定される。  

### errror

`EINTR`
シグナルによって中断された。 signal(7) 参照。

`EINVAL`
usec が 1000000 以上だった。 (これをエラーとみなすシステムのみ)

## kill

kill - プロセスにシグナルを送る  

```c
#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 で指定したシグナルが、 呼び出し元のプロセスがシグナルを送る許可を持つ全てのプロセスに 送られる。<br>但し、プロセス番号 1 (init) へはシグナルは送られない。
-1より小さい値 | ID が -pid のプロセスグループに属するすべてのプロセスに sig で指定したシグナルが送られる。

### 返り値

成功した場合 (少なくとも一つのシグナルが送信された場合)、 0 が返される。エラーの場合 -1 が返され、 errno が適切に設定される。  

### エラー

`EINVAL`
無効なシグナルを指定した。

`EPERM`
呼び出し元のプロセスが、受信するプロセスのいずれに対しても シグナルを送る許可を持っていない。

`ESRCH`
ターゲットプロセスまたはプロセスグループが存在しない。
既存のプロセスはゾンビである可能性があることに注意してください。ゾンビは、実行を終了したものの、まだ待機（2）されていないプロセスです。

## pause

シグナルを待つ

```c
#include <unistd.h>

int pause(void);  
```

pause() は、呼び出したプロセス (またはスレッド) を、そのプロセスを終了させたり、シグナル捕捉関数が起動されるような シグナルが配送されるまで、スリープさせる。

### 返り値

pause() が返るのは、シグナルを受け取りシグナル捕獲関数から返った場合だけである。
この場合は pause() は -1 を返し、 errno に `EINTR` が設定される。

### エラー

`EINTR`
シグナルを受け取り、シグナル捕獲関数から帰ってきた。

## 参考

[Man page of SIGNAL](https://linuxjm.osdn.jp/html/LDP_man-pages/man2/signal.2.html)
[Man page of SIGACTION](https://linuxjm.osdn.jp/html/LDP_man-pages/man2/sigaction.2.html)
[Man page of SIGSETOPS](https://linuxjm.osdn.jp/html/LDP_man-pages/man3/sigsetops.3.html)
[Man page of KILL](https://linuxjm.osdn.jp/html/LDP_man-pages/man2/kill.2.html)
[Man page of PAUSE](https://linuxjm.osdn.jp/html/LDP_man-pages/man2/pause.2.html)
[Man page of SLEEP](https://linuxjm.osdn.jp/html/LDP_man-pages/man3/sleep.3.html)
[Man page of USLEEP](https://linuxjm.osdn.jp/html/LDP_man-pages/man3/usleep.3.html)