信号(IPC)

シグナルとは、実行中のプログラムに送信される標準化されたメッセージであり、終了やエラー処理などの特定の動作をトリガーします。シグナルはプロセス間通信(IPC)の限定的な形式であり、通常はUnixUnix系、その他のPOSIX準拠オペレーティングシステムで使用されます。

シグナルとは、プロセスまたは同じプロセス内の特定のスレッドに送信される非同期通知であり、イベントを通知します。シグナルの一般的な用途は、プロセスの割り込み、一時停止、終了、または強制終了です。シグナルは1970年代のベル研究所のUnixで考案され、後にPOSIX標準で規定されました。

シグナルが送信されると、オペレーティングシステムは対象プロセスの通常の実行フローを中断してシグナルを送信します。実行は、非アトミック命令の実行中に中断される可能性があります。プロセスが以前にシグナルハンドラを登録している場合は、そのルーチンが実行されます。そうでない場合は、デフォルトのシグナルハンドラが実行されます。

シグナルはアルゴリズムの効率性に優れているため、組み込みプログラムでは、シグナルがプロセス間通信に役立つ場合があります。

シグナルは割り込みに似ていますが、割り込みはCPUによって仲介されカーネルによって処理されるのに対し、シグナルはカーネルによって(場合によってはシステムコールを介して)仲介され、個々のプロセスによって処理されるという違いがあります。カーネルは、割り込みをシグナルとして、それを発生させたプロセスに渡すことがあります(代表的な例としては、SIGSEGVSIGBUSSIGILLSIGFPEなどがあります)。

歴史

信号を送る

kill (2)システムコールは、権限が許せば、指定されたプロセスに指定されたシグナルを送信します。同様に、kill(1)コマンドは、ユーザーがプロセスにシグナルを送信できるようにします。raise (3)ライブラリ関数は、指定されたシグナルを現在のプロセスに送信します。

ゼロ除算セグメンテーション違反( SIGSEGV )、浮動小数点例外 ( SIGFPE )などの例外が発生すると、コア ダンプが生成され、プログラムが終了します。

カーネルは、プロセスにイベントを通知するためのシグナルを生成できます。例えば、プロセスがリーダーによって閉じられたパイプに書き込みを行った場合、 SIGPIPE が生成されます。デフォルトでは、このシグナルによってプロセスが終了されるため、シェルパイプラインを構築するときに便利です。

実行中のプロセスの制御端末で特定のキーの組み合わせを入力すると、システムは特定の信号を送信します。[ 3 ]

  • Ctrl-C (古い Unix では DEL) はINTシグナル (「割り込み」、SIGINT ) を送信します。デフォルトでは、これによりプロセスが終了します。
  • Ctrl-ZはTSTPシグナル(「端末停止」、SIGTSTP )を送信します。デフォルトでは、これによりプロセスの実行が中断されます。[ 4 ]
  • Ctrl-\はQUITシグナル ( SIGQUIT )を送信します。デフォルトでは、これによりプロセスが終了し、コアがダンプされます。
  • Ctrl-T(すべてのUNIXでサポートされているわけではない)はINFOシグナル(SIGINFO)を送信します。デフォルトでは、コマンドでサポートされている場合は、オペレーティングシステムが実行中のコマンドに関する情報を表示します。[ 5 ]

最新のオペレーティング システムでのこれらのデフォルトのキーの組み合わせは、 sttyコマンドで変更できます。

信号の処理

シグナルハンドラは、signal(2)またはsigaction(2)システムコールを使用して設定できます。特定のシグナルに対してシグナルハンドラが設定されていない場合は、デフォルトのハンドラが使用されます。設定されている場合、シグナルはインターセプトされ、シグナルハンドラが呼び出されます。プロセスは、ハンドラを作成せずに、シグナルを無視する ( SIG_IGN ) か、デフォルトのシグナルハンドラを使用する ( SIG_DFL ) かの2つのデフォルトの動作を指定することもできます。インターセプトおよび処理できないシグナルが2つあります。SIGKILLとSIGSTOPです

リスク

シグナル処理は競合状態に対して脆弱です。シグナルは非同期であるため、シグナル処理ルーチンの実行中に、別のシグナル(同じ種類のシグナルであっても)がプロセスに送信される可能性があります。

sigprocmask (2)呼び出しは、シグナルの送信をブロックしたりブロック解除したりするために使用できます。ブロックされたシグナルは、ブロック解除されるまでプロセスに送信されません。無視できないシグナル(SIGKILLおよびSIGSTOP)はブロックできません。

シグナルにより、進行中のシステム コールが中断され、非透過的な再起動の管理がアプリケーションに任されることになります。

シグナルハンドラは、望ましくない副作用(例:errno の変更、シグナルマスクの変更、シグナル処理の変更、その他のグローバルプロセス属性の変更)が発生しないように記述する必要があります。シグナルハンドラ内でmallocprintfなどの再入不可能な関数を使用することも安全ではありません。特に、POSIX 仕様と Linux のマニュアルページsignal(7)では、シグナル関数から直接的または間接的に呼び出されるすべてのシステム関数が非同期シグナルに対して安全であることが要求されています。[ 6 ] [ 7 ] signal -safety(7) のマニュアルページには、このような非同期シグナルに対して安全なシステム関数(実際にはシステムコール)のリストが記載されています。それ以外の場合、未定義の動作となります。[ 8 ]シグナルハンドラで何らかの変数を設定し、それを他の場所でテストすることをお勧めします。 [ 9 ]volatile sig_atomic_t

シグナル ハンドラは、代わりにシグナルをキューに入れて、すぐに戻ることができます。メイン スレッドは、イベント ループなどでキューからシグナルが取得されるまで、「中断されることなく」処理を続けます。ここでの「中断されない」とは、前述のように、ブロックされた操作が途中で戻り、再開する必要があることを意味します。シグナルは、ワーカー プールではなく、メイン スレッドのキューから処理する必要があります。ワーカー プールでは非同期性の問題が再び発生するためです。ただし、キューの管理は、 のみでは非同期シグナルに対して安全な方法では不可能です。これはsig_atomic_t、このような変数に対する単一の読み取りと書き込みのみがアトミックであることが保証され、キューに必要なインクリメントや (フェッチと) デクリメントは保証されないためです。したがって、実質的には、sig_atomic_t処理されるまで、ハンドラごとに 1 つのシグナルのみが安全にキューに登録されます。

ハードウェア例外との関係

プロセスの実行によってたとえばプロセスがゼロ除算を試みたり、ページ フォールトが発生したりした場合、ハードウェア例外が生成されることがあります。

Unix系オペレーティングシステムでは、このイベントは自動的にプロセッサコンテキストを変更し、カーネル例外ハンドラの実行を開始します。ページフォールトなどの例外が発生した場合、カーネルはイベント自体を完全に処理し、プロセスの実行を再開するのに十分な情報を持っています。

しかし、他の例外については、カーネルはそれらをインテリジェントに処理することができないため、例外処理を障害が発生したプロセスに委ねる必要があります。この委任はシグナルメカニズムによって実現され、カーネルは現在の例外に対応するシグナルをプロセスに送信します。例えば、x86 CPU上でプロセスが整数のゼロ除算を行おうとすると、除算エラー例外が生成され、カーネルはプロセスに SIGFPEシグナルを送信します。

同様に、プロセスが仮想アドレス空間外のメモリアドレスにアクセスしようとした場合、カーネルはSIGSEGVセグメンテーション違反シグナル)を介してプロセスにこの違反を通知します。シグナル名と例外の正確なマッピングは、例外の種類がアーキテクチャによって異なるため、CPUによって異なります。

POSIXシグナル

以下のリストは、Single Unix 仕様バージョン 5 で規定されているシグナルをまとめたものです。すべてのシグナルはヘッダーファイルでマクロ定数として定義されています<signal.h>。マクロ定数の名前は、「SIG」というプレフィックスと、それに続くシグナルのニーモニック名で構成されます。

プロセスは、受信したPOSIXシグナルの処理方法を定義できます。プロセスがシグナルに対する動作を定義していない場合、そのシグナルのデフォルトのハンドラが使用されます。以下の表は、 FreeBSDOpenBSDLinuxなどのPOSIX準拠のUNIXシステムのデフォルトの動作を示しています。

信号携帯電話番号デフォルトのアクション説明
SIGABRT6終了(コアダンプ)プロセス中止信号
SIGALRM14終了目覚まし時計
SIGBUS該当なし終了(コアダンプ)メモリオブジェクトの未定義部分へのアクセス
SIGCHLD該当なし無視する子プロセスが終了、停止、または続行されました
SIGCONT該当なし続く停止した場合は実行を継続する
SIGFPE8終了(コアダンプ)誤った算術演算
SIGHUP1終了電話を切る
SIGILL4終了(コアダンプ)不正な命令
SIGINT2終了端末割り込み信号
SIGKILL9終了キル(捕まえたり無視したりできない)
SIGPIPE13終了誰にも読まれないパイプに書く
SIGQUIT3終了(コアダンプ)端末終了信号
SIGSEGV11終了(コアダンプ)無効なメモリ参照
SIGSTOP該当なし停止実行を停止します(キャッチまたは無視できません)
SIGSYS該当なし終了(コアダンプ)不正なシステムコール
SIGTERM15終了終了信号
SIGTRAP5終了(コアダンプ)トレース/ブレークポイントトラップ
SIGTSTP該当なし停止ターミナル停止信号
SIGTTIN該当なし停止バックグラウンドプロセスが読み取りを試行しています
SIGTTOU該当なし停止バックグラウンドプロセスが書き込みを試行しています
SIGUSR1該当なし終了ユーザー定義信号1
SIGUSR2該当なし終了ユーザー定義信号2
SIGURG該当なし無視する帯域外データはソケットで利用可能
SIGVTALRM該当なし終了仮想タイマーが切れました
SIGXCPU該当なし終了(コアダンプ)CPU時間制限を超えました
SIGXFSZ該当なし終了(コアダンプ)ファイルサイズの制限を超えました
SIGWINCH該当なし無視するターミナルウィンドウのサイズが変更されました
携帯電話番号:
ほとんどのシグナルでは、対応するシグナル番号は実装定義です。この列にはPOSIX標準で規定されている番号を列挙します。[ 10 ]
アクションの説明:
終了_exit()– プロセスの異常終了。プロセスは、指定されたシグナルによって異常終了を示すステータスを除きwait()、 すべての結果とともに終了しますwaitpid()
終了(コアダンプ)  – プロセスの異常終了。さらに、コアファイルの作成など、実装定義の異常終了アクションが発生する場合があります。
無視 – 信号を無視します。
停止 – プロセスを停止 (または一時停止) します。
続行 – プロセスが停止している場合は続行します。それ以外の場合は、信号を無視します。
SIGABRTシギオット
SIGABRTシグナルは、プロセスに中止(つまり終了)を指示するために送信されます。このシグナルは通常、プロセス自身がC標準ライブラリの関数を呼び出す際に発行されますが、他のシグナルと同様に、外部からプロセスに送信することもできます。abort()
SIGIOT は、CPU が明示的な「トラップ」命令 (定義された関数なし) または実装されていない命令 (エミュレーションが利用できない場合) を実行したことを示します。
注: 「入出力トラップ」は、CPUの「トラップ」命令の誤った名称です。この用語は、主にI/O機能の実装に用いられた初期の用途を反映していますが、これらの命令は本質的にデバイスI/Oに結びついているわけではなく、仮想ホストと実ホスト間の通信など、他の目的にも使用されることがあります。
SIGIOTSIGABRT は通常同じ信号であり、その信号を受信すると上記のいずれかの状態を示している可能性があります。
シガルムSIGVTALRMシグプロフ
SIGALRM 、SIGVTALRM、およびSIGPROFシグナルは対応する時間制限に達したときにプロセスに送信されます。プロセスは、またはを呼び出すことによってこれらの時間制限を設定します。SIGALRM時間制限は実時間またはクロック時間に基づきます。SIGVTALRMプロセスが使用するCPU時間に基づきます。SIGPROFはプロセスと、プロセスに代わってシステムによって使用されるCPU時間(プロファイリングタイマーと呼ばれる)に基づきます。一部のシステムでは、SIGALRM は関数の実装によって内部的に使用される場合があります。alarmsetitimersleep
シグバス
SIGBUSシグナルはバスエラーが発生したときにプロセスに送信されます。このシグナルが送信される条件としては、例えば、メモリアクセスのアラインメントが不適切であったり、物理アドレスが存在しないことが挙げられます。
シグナル
SIGCHLDシグナルは、子プロセスが終了、停止、または停止後に再開したときにプロセスに送信されます。このシグナルの一般的な用途の一つは、システムコールを明示的に呼び出すことなく、子プロセスが終了した後に子プロセスが使用したリソースをクリーンアップするようオペレーティングシステムに指示することです。wait
シグナルコント
SIGCONTシグナル、 SIGSTOPシグナルまたはSIGTSTPシグナルによって一時停止されたプロセスを再開(再開)するようオペレーティングシステムに指示します。このシグナルの重要な用途の一つは、Unixシェルにおけるジョブ制御です。
SIGFPE
SIGFPEシグナル、浮動小数点演算または整数演算ハードウェアで例外的な(必ずしもエラーとは限らない)状態が検出された場合にプロセスに送信されます。これには、ゼロ除算、浮動小数点アンダーフローまたはオーバーフロー、整数オーバーフロー、無効な演算、または不正確な計算が含まれます。動作はハードウェアによって異なる場合があります。
SIGHUP
SIGHUPシグナルは、プロセスの制御端末が閉じられた際に送信されます。元々は、シリアル回線の切断(ハングアップ)をプロセスに通知するために設計されました。現代のシステムでは、このシグナルは通常、制御用の擬似端末または仮想端末が閉じられたことを意味します。[ 11 ]多くのデーモン(制御端末を持たないデーモン)は、このシグナルの受信を、終了する代わりに設定ファイルの再読み込みとログファイルのフラッシュ/再オープンの要求と解釈します。[ 12 ] nohupは、コマンドにシグナルを無視させるコマンドです。
印章
SIGILLシグナルは、プロセス不正、不正、不明、または特権命令を実行しようとしたときに、そのプロセスに送信されます。
シギント
SIGINTシグナルはユーザーがプロセスを中断したい場合に、制御端末からプロセスに送信されます。これは通常、 +キーを押すことで開始されますが、一部のシステムでは「Delete」キーまたは「Break」キーも使用できます。[ 13 ]CtrlC
シグナルキル
SIGKILLシグナルは、プロセスを即時終了(kill )させるために送信されます。SIGTERMやSIGINTとは異なり、このシグナルはキャッチまたは無視することはできず、受信側プロセスはこのシグナルを受信した際にいかなるクリーンアップも実行できません。以下の例外が適用されます。
  • ゾンビ プロセスはすでに終了しており、親プロセスによる処理を待機しているため、強制終了することはできません。
  • ブロックされた状態にあるプロセスは、再び起動するまで終了しません。
  • initプロセスは特別です。処理したくないシグナルは受け取らないので、SIGKILLを無視することができます。[ 14 ]このルールの例外は、initがLinux上でptraceされている場合です[ 15 ] [ 16 ]
  • 割り込み不可のスリープ状態にあるプロセスは、 SIGKILLを送信しても終了しない(つまりリソー​​スを解放しない)場合があります。これは、一時的なソフトウェアの問題を解決するために UNIX システムを再起動する必要がある数少ないケースの 1 つです。
SIGKILLは、ほとんどのシステムシャットダウン手順において、 SIGTERMに応答して自発的に終了しないプロセスを終了する際の最後の手段として使用されます。Mac OS X 10.6( Snow Leopard )では、コンピュータのシャットダウン手順を高速化するために、 「クリーン」とマークされたアプリケーションにSIGKILLを送信します。これにより、おそらく悪影響はなく、シャットダウン時間が短縮されます。[ 17 ]このコマンドは、Linuxなどで実行された場合、同様の危険な効果をもたらします。つまり、プログラムが未保存データを保存できないようにするのです。他のオプションもありますが、何も指定しない場合は、より安全なSIGTERM信号が使用されます。killall -9
シグパイプ
SIGPIPEシグナルはもう一方の端にプロセスが接続されていない状態でパイプに書き込もうとしたときに、プロセスに送信されます。
シグナルポール
SIGPOLLシグナルは、明示的に監視されているファイル記述子でイベントが発生したときに送信されます。[ 18 ]これを使用すると、カーネルが呼び出し元の代わりに記述子をポーリングするため、実質的に非同期I/O要求が可能になります。これは、アクティブポーリングの代替手段となります。
SIGRTMINからシグルートマックス
SIGRTMINからSIGRTMAXまでの信号はユーザー定義の目的で使用されるリアルタイム信号です。
SIGQUIT
SIGQUITシグナルは、ユーザーがプロセスを終了してコア ダンプを実行するように要求したときに、制御端末によってプロセスに送信されます。
SIGSEGV
SIGSEGVシグナルはプロセスが無効な仮想メモリ参照を行ったとき、つまりセグメンテーション違反を起こしたときにプロセスに送信されます。[ 19 ]
シグストップ
SIGSTOPシグナルは後で再開できるようにプロセスを停止するようにオペレーティング システムに指示します。
シグシス
SIGSYSシグナルは、プロセスがシステムコールに不正な引数を渡したときに送信されます。実際には、アプリケーションがライブラリ(例:libc)を利用してシステムコールを実行するため、この種のシグナルはほとんど発生しません。SIGSYS、Linux Seccompのセキュリティルールに違反するアプリケーションによって受信される可能性があります。SIGSYS、Linux上でWindowsのシステムコールをエミュレートするなど、外部のシステムコールをエミュレートするためにも使用されます。[ 20 ]
シグナルターミナル
SIGTERMシグナルは、プロセスの終了を要求するために送信されます。SIGKILL シグナルとは異なりプロセスはこれをキャッチして解釈したり無視したりできます。これにより、プロセスはリソースを解放し、適切な場合には状態を保存して適切な終了を行うことができます。SIGINTSIGTERMとほぼ同じです。
シグナルTP
SIGTSTPシグナルは、制御端末からプロセスに停止terminal st o p を要求するために送信されます。通常、ユーザーが+ キーを押すことで開始されます。SIGSTOPとは異なり、プロセスはこのシグナルに対してシグナルハンドラを登録したり、シグナルを無視したりできます。CtrlZ
SIGTTINシグトゥ
SIGTTINおよびSIGTTOUシグナルはバックグラウンドでプロセスがttyから読み込みまたは書き込み行おうとしたときに送信されます。通常、これらのシグナルはジョブ制御下にあるプロセスによってのみ受信されます。デーモンには制御端末がないため、これらのシグナルを受信することはありません。
シグトラップ
SIGTRAPシグナルは、例外 (またはトラップ) が発生したときにプロセスに送信されます。例外とは、デバッガーが通知を要求した条件です。たとえば、特定の関数が実行されたときや、特定の変数の値が変更されたときなどです。
シグルグ
ソケットに読み取り可能な緊急データまたは帯域外データがある場合、 SIGURGシグナルがプロセスに送信されます。
SIGUSR1SIGUSR2
SIGUSR1およびSIGUSR2シグナルはユーザー定義の条件を示すためにプロセスに送信されます。
SIGXCPU
SIGXCPUシグナルは、プロセスがCPUを一定のユーザー設定可能な値を超えて使い果たした場合に、そのプロセスに送信されます。[ 21 ] SIGXCPUシグナルの到着により、受信側プロセスは、オペレーティングシステムによってSIGKILLシグナルを使用して終了される前に、中間結果をすばやく保存し、正常に終了する機会が得られます。
SIGXFSZ
SIGXFSZシグナルはファイル サイズが最大許容サイズを超えたときにプロセスに送信されます。
シグウィンチ
SIGWINCHシグナルは、プロセスの制御端末のサイズが変更されたとき(ウィンドウ変更)にプロセスに送信されます。[ 22 ]

その他の信号

以下のシグナルはPOSIX仕様では規定されていません。ただし、様々なシステムで使用されることがあります。

シゲムト
SIGEMTシグナルは、エミュレータトラップが発生したときにプロセスに送信されます。エミュレータとは通常、他のプログラムを実行するソフトウェアを指しますが、この場合はプログラムがスーパーバイザ呼び出し命令を実行したことを意味します( DEC PDP-11シリーズのコンピュータでは、EMT命令がこの目的のために使用されていました)。
署名情報
SIGINFOシグナルは制御端末からステータス (情報) 要求を受信したときにプロセスに送信されます。
SIGPWR
SIGPWR信号は、システムに電源障害が発生したときにプロセスに送信されます。
シグロスト
ファイルロックが失われたときに、 SIGLOSTシグナルプロセスに送信されます。
SIGSTKFLT
SIGSTKFLTシグナルは、コプロセッサがスタックフォールト(スタックが空のときにポップしたり、スタックがいっぱいのときにプッシュしたりすること)を経験した場合にプロセスに送信されます。[ 23 ]これLinuxで定義されていますが、使用されていません。Linuxでは、x87コプロセッサのスタックフォールトは代わりにSIGFPEを生成ます[ 24 ]
署名済み
SIGUNUSEDシグナルは未使用のシステムコール番号を持つシステムコールが発行されたときにプロセスに送信されます。ほとんどのアーキテクチャではSIGSYSと同義です。[ 23 ]
SIGCLD
SIGCLD信号SIGCHLDと同義である。[ 23 ]

参照

参考文献

  1. ^ McIlroy, MD (1987). A Research Unix reader: annotated excerpts from the Programmer's Manual, 1971–1986 (PDF) (技術レポート). CSTR. ベル研究所. 139.
  2. ^ Gagliardi, Pietro. 「Bell LabsのPlan 9でのCプログラミング」 . doc.cat-v.org . 2022年1月22日閲覧
  3. ^ 「終了シグナル」。GNU Cライブラリ
  4. ^ 「ジョブ制御信号」 . GNU Cライブラリ.
  5. ^ 「その他のシグナル」 . GNU Cライブラリ.
  6. ^ 「The Open Group Base Specifications Issue 6、IEEE Std 1003.1、2004年版:システムインターフェース第2章」。pubs.opengroup.org2020年12月20日閲覧
  7. ^ "signal(7) - Linuxマニュアルページ" . man7.org . 2020年12月20日閲覧
  8. ^ "signal-safety(7) - Linuxマニュアルページ" . man7.org . 2020年12月20日閲覧
  9. ^ 「The Open Group Base Specifications Issue 6、IEEE Std 1003.1、2004年版: <signal.h>」 . pubs.opengroup.org . 2020年12月20日閲覧
  10. ^ "IEEE Std 1003.1-2017 - kill" . IEEE, Open Group.整数値と使用されるsig値の対応は以下のリストに示されています。以下にリストされている以外のsignal_numberを指定した場合の効果は未定義です。
  11. ^ Michael Kerrisk (2009年7月25日). "signal(7)" . Linuxプログラマーズ・マニュアル(バージョン3.22) . Linuxカーネル・アーカイブ. 2009年9月23日閲覧
  12. ^ "perlipc(1)" . Perlプログラマーズリファレンスガイド、バージョン5.18 . perldoc.perl.org - Perlプログラミング言語の公式ドキュメント. 2013年9月21日閲覧。
  13. ^ 「SIGINTとSIGQUITの適切な処理」 。 2012年10月6日閲覧
  14. ^ https://manpages.ubuntu.com/manpages/zesty/man2/kill.2.htmlアーカイブ2018年1月28日Wayback Machineセクション NOTES
  15. ^ 「SIGKILL initプロセス(PID 1)」Stack Overflow
  16. ^ 「root で init プロセスを強制終了できますか?」 Unix & Linux Stack Exchange
  17. ^ 「Mac Dev Center: Mac OS Xの新機能: Mac OS X v10.6」。2009年8月28日。 2017年11月18日閲覧
  18. ^ 「ioctl - STREAMデバイスを制御する」 . POSIXシステムコール仕様. The Open Group . 2015年6月19日閲覧
  19. ^ 「「セグメンテーション違反」とは何ですか?」support.microfocus.com . 2018年11月22日閲覧
  20. ^ 「Syscall User Dispatch – Linuxカーネルドキュメント」 . kernel.org . 2021年2月11日閲覧
  21. ^ 「getrlimit、setrlimit - 最大リソース消費量を制御する」 POSIXシステムコール仕様。The Open Group 。 2009年9月10日閲覧
  22. ^ Clausecker, Robert (2017年6月19日). 「0001151: 端末ウィンドウサイズを取得/設定するための新しいシグナルSIGWINCHと関数tcsetsize()、tcgetsize()を導入」 . Austin Group Defect Tracker . Austin Group . 2017年10月12日閲覧. Accepted As Marked
  23. ^ a b c "signal(7) — Linuxマニュアルページ" . manpages.courier-mta.org . 2018年11月22日閲覧
  24. ^ 「Linux 3.0 x86_64: SIGSTKFLT はいつ発生するのか?」 . Stack Overflow .