Linux Signalの例

10038 ワード

信号は、システムがいくつかの条件に応答して生成したイベントであり、そのメッセージを受信したプロセスは、対応する処理を行う.通常、メッセージは、セグメントエラー(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);

    ここで、sigsignal numberであり、actは信号の処理動作を指定し、oactNULLでなければ信号の前の処理動作を返す.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は主に以下の値に設定できます.
  • SA_NOCLDSTOPサブプロセス停止時にSIGCHLD信号
  • は発生しない.
  • SA_RESETHANDは、信号の処理関数を処理関数の入口でSIG_DFL
  • にリセットする.
  • SA_RESTARTは、EINTRエラー
  • を与えるのではなく、中断可能な関数を再起動する.
  • SA_SIGINFOは、sa_sigactionを信号とする処理関数
  • を用いる
  • SA_NODEFERは、信号をキャプチャする際に、信号マスクワード
  • に追加しない.
    簡単なコードの例は次のとおりです.
    #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は以前のシールドワードセットであり、howsetがどのように有効になるかを制御しており、以下の値に設定することができる.
  • SIG_BLOCKプロセスのマスクワードセットは、当期のマスクワードセットとsetとの並列セットとなり、setにはマスクが必要な信号セット
  • が含まれる.
  • SIG_UNBLOCKプロセスのシールドワードセットは、当期のシールドワードセットとsetの補完セットとの交差であり、setには、シールドを解除する必要がある信号セット
  • が含まれる.
  • SIG_SETMASKプロセスのマスクワードセットは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以下の場合、以下のようになる.
  • =0信号は、送信者が存在するグループに送信される全プロセス
  • に送信される.
  • =1の信号は、すべてのプロセス
  • に送信される.
  • より小さい信号は、プロセスグループ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)