これまで
シェルもどき「oreshell」を自作している。
前回は、ジョブ制御とは何かについて調べた。また、ジョブ制御には「シグナル」を使っていることがわかった。
今回はシグナルについて調べる。
シグナル(英: signal)とは、Unix系(POSIX標準に類似の)オペレーティングシステム (OS) における、限定的なプロセス間通信であり、プロセスに対し非同期でイベントの発生を伝える機構である。シグナルが送信された際、OSは宛先プロセスの正常な処理の流れに割り込む。どんな不可分でない処理の間でも割り込むことができる。受信プロセスが以前にシグナルハンドラを登録しておけば、シグナル受信時にそのルーチンが実行される。さもなくば、デフォルトのシグナル処理が行われる。wikipediaより
「シグナル」はプロセス間で通信を行うための信号である。
シグナルを受け取ったプロセスはプロセス自身が持つ「表」に従ってその動作を決定する。
以下のような永久ループするプログラム(go言語)があったとする。
実行すると
永久ループするプログラムなので当然ながら、延々と実行を続ける。
このプロセスを外部から停止したいとする。
いろいろ方法があるが、ここでは以下の二つの方法を行う。
別の端末で、永久ループしているプロセスのIDを調べる
永久ループしているプロセスIDを指定してkillコマンドを実行する。
そうすると
永久ループしているプロセスが停止する。
停止までの処理を図にすると以下の通り。
プロセスIDのみ指定してkillコマンドを実行すると、そのプロセスに対してシグナル「SIGTERM」を送る。
プロセスはSIGTERMを受け取ると、表からそれを探し出し、デフォルトアクション「プロセス終了」を実行する。
killコマンドはその名の通りプロセスを殺すためによく使われるが、プロセス終了(SIGTERM)以外のシグナルを送ることもできる。以下は例。
先ほどと同様に永久ループするプログラムを実行し、端末から「Ctrl+C」キーを押下する。
永久ループしているプロセスが停止する。
停止までの処理を図にすると以下の通り。
端末は、特定のキーとそれに対応する特殊制御文字を一覧にした表を持つ。
特殊制御文字は、端末に結び付いたフォアグラウンドプロセスグループやその標準入力を制御するためのものである。
端末に特定のキーを入力すると表に従って特殊制御文字の処理を実行する。
その表は「stty」コマンドで確認できる。
通常、「Ctrl+C」キーには特殊制御文字「INTR(割り込み)」が割り当てられる。
INTRは、端末に関連付けられたフォアグラウンドプロセスグループの全プロセスに対してシグナル「SIGINT」を送る。(参考)
プロセスはSIGINTを受け取ると、表からそれを探し出し、デフォルトアクション「プロセス終了」を実行する。
プロセスのシグナル受信時のアクションとしてユーザが定義したアクションを、プログラム中で割り当てることができる。
go言語によるサンプルプログラムで例を示す。
実行すると
延々と実行を続ける。
端末から「Ctrl+C」キーを押下すると
前回と違いプロセスを終了しない。
代わりに
「interrupt を受け付けた」
「ここでなんらかのアクションを実行する」
を表示した。
プログラム中で任意のシグナル(ここではSIGINT)についてユーザ定義アクションを設定すると、シグナル受信時にデフォルトアクションではなくユーザ定義アクションを実行する。(ただし、SIGKILLとSIGSTOPは指定不可)
よって、signal_sampleプロセスはプロセス終了をせずにユーザ定義アクションを実行し、そのあと永久ループを続けた。
先ほどと同じように、別の端末で永久ループしているプロセスのIDを調べ、永久ループしているプロセスIDを指定してkillコマンドを実行する(シグナル「SIGTERM」を送る)。
そうすると
前回と同じく、永久ループしているプロセスが停止する。
シグナル「SIGTERM」についてはユーザ定義アクションを指定していないためデフォルトアクション(プロセス終了)を実行した。
次回からoreshellのジョブ制御の実装を進める。