Linuxカーネルのシグナルについて調べてみた

概要

詳解Linuxカーネル読書会に参加して詳解Linuxを参考にkernel 4.4.0のシグナル部分のソースを読んでみた。

シグナルの種類

1-31が通常シグナル。32-64がリアルタイムシグナル。

シグナル送信(send_signal)

よくプロセスをkillするのに使うkill関数はkillシステムコールを呼ぶようなのでその実装を見てみる。

kernel/signal.cで定義される。

実態はkill_something_info関数っぽい。

kill_something_infoはpidが0より大きければ、rcu_read_lock()をとって、kill_pid_info関数を実行。kill_pid_info関数ではpidからtask_struct構造体を取得して、group_send_sig_info関数にシグナルと共に渡す。group_send_sig_info関数は、check_kill_permission関数でプロセスをkillしてもいいかパーミッションのチェックを行う。
パーミッションがOKならdo_send_sig_info関数->send_signal関数->__send_signal関数の順で呼ばれる。

__send_signal関数がシグナルを送るための本体のようだ。リアルタイムシグナルだとキューを作成する。

キューがあれば対象プロセスのtask_struct構造体のpendingメンバのリストをキューの末尾に追加。その後、キューにsiginfo構造体をコピー。

シグナル送信の実態はout_setラベル以降?リアルタイムシグナルじゃなければ、キューのところは飛ばされて一気にout_setに来る。signalfd_notify関数でスレッドがブロックされてれば起こす。sigaddset関数で送信するシグナルに対応するビットを立てる。complete_signal関数でプロセスのすべてのスレッドにシグナル情報セットして(多分)、send_signal終了!

シグナル受信(do_signal)

do_signal関数でシグナルの受信処理がされる。

do_signalの肝の部分はget_signal関数内のdequeue_signal関数を繰り返し実行する部分。

dequeue_signalしたあとは以下のようにsigaction構造体を取得し、ka変数に保存する。ka->sa.sa_handlerSIG_DFL以外ならbreakしてdequeueのforを抜ける。

for文を抜けるとsignrが0より大きのでreturnでtrueが返される。

get_signalがtureを返すとhandle_signal関数が実行される。handle_signal関数でプロセスがシグナルを受け取る。handle_signalはsetup_rt_frame関数を呼び出しユーザーモードスタックをシグナル処理用に設定する。
2.6系で存在したsetup_frame関数はなくなって以下のようになっている模様。x32が何を指すのかはよくわからない。

32bitモード 64bitモード
SA_SIGINFOない ia32_setup_frame __setup_rt_frame
SA_SIGINFOある ia32_setup_rt_frame __setup_rt_frame

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です