タダノキロク

日々の考えたことの記録 主に無駄なこと

詳細Linuxカーネル 11章 シグナル 5/15

詳細Linuxカーネル 11章 シグナル 5/15

カーネルのシグナル処理方法とプロセス間でシグナル交換するためのシステムコールを学ぶ。

https://kernelreading.doorkeeper.jp/events/42462

11.1章 シグナルの役割

シグナルはプロセスに送る短いメッセージのこと。 シグナルの利用目的は
* ある事象が発生したことをプロセスに通知。
* プロセスのコード無いにあるシグナルハンドラをシグナルを受けたプロセスに実行
の2つ。ただし、多くの場合は2つが同時に実行される。
(ある事象Aが起きたからある処理[1]を実施のような使われ方)

通常のシグナルはシグナル番号1-31を使用して、 リアルタイムシグナルは32-64を使用する。
2つの違いは同じ種類のシグナルの実行回数。
通常のシグナルは同じ種類のシグナルを2回以上プロセスが受けても、 1つだけ受信して処理を行う。
リアルタイムシグナルは待ち行列に並んで、順に実施される。

(通常のシグナルを受けた場合の動作は[終了/停止/ダンプ]といった、
2回以上実施に意味のないものだからか?)

シグナルの送信やシグナル受診時の動作を決めるためのシステムコールが準備されている。

シグナルの送受信は以下の2段階で実施。
1. シグナルの生成
送信元がシグナルの送信先(受信側)プロセスのデータ構造にシグナル情報を追加。
シグナル情報は保留中シグナルとして追加される(&signals->list)。
これは、シグナル送信時に送信先プロセスがCPU上で動作していない可能性があり、シグナル処理を遅延させるため。

  1. シグナルの配信

シグナル到着の感知は割込みハンドラや例外ハンドラの終了しユーザモードに復帰するたびに実施。
シグナル到着を感知したカーネルが、プロセスの実行状態の変更及び登録しているシグナルハンドラの実行をプロセスにさせる。

11.3章 シグナルの役割

シグナルの配信について具体的に見ることにする。
プロセスディスクリプタTIF_SIGPENDINGフラグの確認によって感知する。
ブロックしていない保留シグナルは、カーネルdo_signalでシグナル配信を行う。

static void do_signal(struct pt_regs *regs)
{
  struct ksignal ksig;

  if (get_signal(&ksig)) {
    /* Whee!Actually deliver the signal.  */
    handle_signal(&ksig, regs);
    return;
  }

get_signalの主な処理はシグナルキューにいるsignalの情報をdequeue_signal(実体は__dequeue_signal)でシグナルの情報siginfo_t ksig->infoを取ってくる。
シグナル情報にはシグナル番号/シグナルの発生元のコード(表11-8参照)のようなメンバがある。

signr = dequeue_signal(current, &current->blocked, &ksig->info);

取ってきたシグナル番号のハンドラ持ってくる。

  ka = &sighand->action[signr-1];

もってきたハンドラがデフォルトのハンドラでなければハンドラの情報をコピー。
これを繰り返して遅延しているハンドラをすべて取得。
最後に、ハンドラを追加する。

メモ

"致命的" = プロセスがシグナルハンドラによらずカーネルによって殺されること。
SIGKILLシグナルや、標準設定動作が終了でありながらプロセスが捕捉しない場合などが"致命的"となる。