Linux信号メカニズムと信号処理


信号(signal)はLinuxプロセス間通信のメカニズムであり、全称はソフト割り込み信号であり、ソフト割り込みとも呼ばれる.信号は本質的にソフトウェア階層におけるハードウェア中断機構のシミュレーションである.他のプロセス間通信方式(例えばパイプ、共有メモリなど)に比べて、信号が伝達できる情報は粗く、整数にすぎない.しかし、伝達される情報量が少ないため、信号の管理と使用も容易であり、プロセスの終了、中止、またはリカバリなどのシステム管理に関連するタスクに使用することができる.各信号は、システムヘッダファイルで定義されるSIGCHLD、SIGINTなどのSIGで始まる整数定数マクロで表される.信号はカーネル(kernel)によって管理され、生成方法は多種多様である.
  • は、ハードウェアエラー、メモリ読み取りエラー、分母が0の除算など、カーネル自体によって生成され、カーネルは対応するプロセスに通知する必要がある.
  • は、他のプロセスによって生成され、カーネルによってターゲットプロセスに伝達されてもよい.

  • 信号伝達のプロセス:
  • カーネルには、プロセスごとに信号を保存するテーブルがあります.
  • カーネルがプロセスに信号を渡す必要がある場合、そのプロセスに対応するテーブルに信号を書き込み、信号を生成する.
  • プロセスがユーザ状態からカーネル状態に陥り、再びユーザ状態に切り替わる前に、テーブル内の信号が表示される.信号があれば、プロセスはまず信号に対応する操作を実行し、この場合を実行信号と呼ぶ.
  • 信号が生成されてから対応するプロセスに信号が伝達されるまでの間、信号は待機状態にある.
  • 我々は、プロセスがブロックをキャンセルしたり、信号を無視したりするまで、プロセスがいくつかの信号をブロックする、すなわち、これらの信号を常に待機状態にするコードを記述することができる.

  • しんごうしゅるい
    次の表に、一般的な信号を示します.
    しんごうめい
    数値表示
    説明
    SIGHUP
    1
    端末が停止または制御プロセスが終了します.ユーザがShellを終了すると、プロセスによって開始されたすべてのプロセスがこの信号を受信し、デフォルトではプロセスを終了します.
    SIGINT
    2
    キーボードが切断されました.ユーザがコンビネーションキーを押すと、ユーザ端末は、実行中の端末によって起動されたプログラムにこの信号を送信する.デフォルトのアクションは、プロセスを終了します. 
    SIGQUIT
    3
    キーボードの終了キーが押されます.ユーザがキーを押したり組み合わせたりすると、ユーザ端末は、実行中の端末によって起動されたプログラムにこの信号を送信する.デフォルトのアクションは終了プログラムとして使用されます.
    SIGFPE
    8
    致命的な演算エラーが発生した場合に発行します.浮動小数点演算エラーだけでなく,オーバーフローや除数0などすべてのアルゴリズムエラーも含まれる.デフォルトでは、プロセスを終了しcoreファイルを生成します.
    SIGKILL
    9
    無条件にプロセスを終了します.プロセスは、この信号を受信するとすぐに終了し、クリーンアップおよび一時保存は行われません.この信号は無視、処理、ブロックできません.システム管理者にプロセスを殺す方法を提供します.
    SIGALRM
    14
    タイマがタイムアウトし、デフォルトは終了プロセスとして動作します.
    SIGTERM
    15
    プログラム終了信号はkillコマンドで生成できます.SIGKILLとは異なり、SIGTERM信号はブロックされ、終了することができ、プログラムが終了する前に作業を保存したり、一時ファイルをクリーンアップしたりすることができる.
    kill-lコマンドを使用すると、システムがサポートするすべての信号を表示できます.
    $ 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

    上記は1つのプレゼンテーションにすぎませんが、Linuxリリースでサポートされている信号が異なる場合があります.各信号にはデフォルトの動作があります.デフォルトの動作は、スクリプトまたはプログラムが信号を受信したデフォルトの動作です.一般的なデフォルト動作としては、終了プロセス、終了プログラム、信号無視、一時停止を再起動するプロセスなどがありますが、上記の表では一部のデフォルト動作についても説明しています.
    送信信号
    プログラムまたはスクリプトに信号を送信する方法はいくつかあります.たとえば、結合キーを押すとSIGINT信号が送信され、現在のプロセスが終了します.killコマンドで信号を送信することもできます.構文は次のとおりです.
    $ kill -signal pid

    signalは送信する信号であり、信号名または数値であってもよい.pidは、受信信号のプロセスIDである.例:
    $ kill -1 1001

    プロセスID 1001のプログラムにSIGHUP信号が送信され、プログラムは実行を終了します.また、ID 1001を強制的に殺すプロセス:
    $ kill -9 1001

    キャプチャしんごう
    通常、プロセスを直接終了することは望ましくありません.たとえば、を押すと、プロセスがすぐに終了し、作成した一時ファイルがクリーンアップされず、システムのゴミが発生したり、進行中の作業が保存されたりしないため、やり直しが必要になります.プログラムによりこれらの信号をキャプチャすることができ、終了信号が現れた場合、まずクリアランスと保存処理を行い、プログラムを終了することができる.ユーザプログラムはC/C++などのコードで信号をキャプチャすることができ、これはLinux Cプログラミングで説明されるが、ここではLinuxコマンドで信号をキャプチャする場合にのみ説明する.trapコマンドで信号をキャプチャできます.構文は次のとおりです.
    $ trap commands signals

    commandsはLinuxシステムコマンドまたはユーザーカスタムコマンドです.signalsは、取得する信号であり、信号名または数値であってもよい.信号をキャプチャすると、次の3つの処理が可能になります.
  • 一時ファイルのクリーンアップなどの処理を行うスクリプトを実行します.
  • は、信号のデフォルト動作を受信(復元)する.
  • 現在の信号は無視されます.

  • 1)一時ファイルの整理
    スクリプトが終了信号をキャプチャした後の一般的な動作は、一時ファイルをクリーンアップすることです.例:
    $ trap "rm -f $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 2

    ユーザーが押すと、スクリプトは一時ファイルwork 1$$とdataout$$をクリーンアップしてから終了します.注:exitコマンドは必須です.そうしないと、スクリプトは終了ではなく信号をキャプチャした後に実行を続行します.上のスクリプトを修正し、SIGHUPを受信したときと同じ操作を行います.
    $ trap "rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 1 2

    次の点に注意してください.
  • 複数のコマンドを実行する場合は、コマンドを引用符で囲む必要があります.
  • スクリプトがtrapコマンドを実行した場合にのみ信号がキャプチャされる.
  • が再び信号を受信すると、同様の動作も実行される.

  • 上のスクリプトでは、trapコマンドを実行するとWORKDIRと$$の値が置き換えられます.SIGHUPまたはSIGINT信号を受信したときに値を置き換える場合は、コマンドを一重引用符で囲みます.たとえば、次のようになります.
    $ trap 'rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit' 1 2

    2)信号無視
    trapコマンドのcommandsが空の場合、受信した信号は無視されます.つまり、処理もデフォルトの動作も実行されません.例:
    $ trap '' 2

    複数の信号を同時に無視することもできます.
    $ trap '' 1 2 3 15

    注意:引用符で囲まれている必要があります.次の形式では書けません.
    $ trap  2

    3)デフォルト動作の復元
    信号のデフォルト動作を変更してからデフォルト動作を再開したい場合は、trapコマンドのcommandsを省略すればよい.例えば、
    $ trap 1 2

    SIGHUPとSIGINT信号のデフォルト動作が復元されます.