katsuhiro -> katsuhiro/refmon -> katsuhiro/refmon/signal
シグナル周りのエミュレーション†
最低でも sigaction でシグナルハンドラが指定されたかどうか、停止を引き起こすシグナルのデフォルト処理、SIGKILL あるいは SIGCONT による強制的な実行再開の 3つはエミュレートしないとだめなようだ。
シグナルのエミュレーションがないと起こる問題†
- シェルのサスペンド、レジューム機能が使えない。
- 他にも微妙におかしくなるものがある。
実装でつまづいた点†
- 問題: SIGALRM が飛んだあと、Ctrl+Z でサスペンドすると、シェルで fg しても再開されない。
- 原因: wait で SIGCONT(18) がきたら RUNNING 状態に移るようにしていたのだが、シグナルは若い順から受け取るので、SIGALRM(14) があるとそちらを先に受け取ってしまい、RUNNING 状態に遷移せず、次に進める処理が働かない。そのため止まってしまう。たぶん…。
- 解決: sys_kill をフックして、SIGKILL や SIGCONT が来ていたら RUNNING に切り替えるようにした。
- sys_kill
- SIGKILL あるいは SIGCONT が来たときはプロセスを RUNNING 状態に変更しなければならないので、kill の呼び出し時にやっている。
- sys_sigaction, sys_rt_sigaction
- ハンドラをプロセス情報クラスに記録している。一応 SA_RESETHAND (昔の SA_ONESHOT) は処理しているが他はまだ作っていない。
- sys_signal
- System V のシグナルハンドラ登録用の関数である。Linux では sys_sigaction を呼んでいるだけ。
シグナルを受け取る順番†
リアルタイムシグナルを除くと、シグナルは若い番号から受け取られていく。
sigaction と sigprocmask†
自分自身良くわかってなかったのでメモしておく。
sigprocmask でマスクしたときは、そもそもシグナルがカーネルからプロセスに送信されないのでリファレンスモニタにもシグナルが届かない。
sigaction で無視にしたときはカーネルからプロセスに送信されるが、プロセス側で何もしないで捨てるというだけなので、リファレンスモニタにもシグナル自体は届く。そのため、SIGSTOP や SIGCONT のような wait と関わるシグナルと、SIGTSTP, SIGTTOU, SIGTTIN などに設定されたハンドラは記録しておかなければいけない。
clone のシグナルハンドラのテーブルを共有する処理をエミュレーションする必要がありそう。
シグナルで割り込まれたシステムコールの問題†
- システムコールが ERESTARTSYS で帰ってきたら、シグナルハンドラが終わったときにシステムコールの続き(-1 番という番号で来る)が実行される。ということはもう一回スタックに積んでおけばいいのか?
謎の現象†
監視しているプロセスに kill で以下のシグナルを送ると、リファレンスモニタが 2回同じシグナルをキャッチする。なぜ?
- SIGTSTP 端末 (tty) より入力された一旦停止 (stop)
- SIGTTIN バックグランドプロセスの tty 入力
- SIGTTOU バックグランドプロセスの tty 出力
デフォルトの動作が Stop のシグナルがあやしいのかと思ったが、そんなわけもなく。以下は正常にキャッチされるシグナルである。