|
|
|
| 2008/10/07 11:44||▲
|
|
|
個々の関数の実装に入る前に、シグナル処理ルーチンをどう扱うべきかについて、決めておきたいと思います。
そしてsignal関数の第2引数が関数を指している(すなわち、SIG_DFLやSIG_IGNではない)場合、シグナル sig が発生すると、シグナル処理ルーチンが呼び出される前に、次に挙げる動作のいずれかが行われます(処理系定義)。
- signal(sig, SIG_DFL);と同等のことを実行する。
- 少なくとも sig を含むシグナルの処理系定義の組に対して、処理系がそれらの発生を遮る(この状態は、その時点のシグナル処理ルーチンが完了された時点で元に戻される)。
多くの処理系では1.が採択されています。というより、C99より前の規格では、1.しかなかったように記憶しています。1.では、通常シグナル処理ルーチンの中で再度signal関数が呼び出されることになりますが、それより前に同じシグナルが発生してしまうことを防げないため、いろいろと問題があります。
可能であれば2.の方が優れている気もしますが、2.を実現するにはやや問題があります。というのは、raiseまたはabort関数の結果としてシグナル処理ルーチンが呼び出された場合、longjmp関数で脱出できる必要があるわけですが、シグナルを遮ってしまうと、それを元に戻すことができなくなるからです。
2.の方法でlongjmp関数を使った場合の問題点を回避するには、longjmp関数自体を修正する必要がありますが、下手なことをやるといろいろなところへの悪影響が懸念されるので、今回は素直に1.の方法を採用することにします。
次に、シグナル処理ルーチンが呼び出されるコンテキストをどうするかですが、今回は、すべてタスクコンテキストで呼び出されるものとします。割り込みハンドラやCPU例外ハンドラ(H8はCPU例外をサポートしませんが)などの非タスクコンテキストから直接呼ぶのではなく、いったんiras_texでタスク例外を発生させてから、シグナル例外処理ルーチンを呼び出すものとします。
このように、タスク例外処理ルーチンからシグナル処理ルーチンが呼ばれることになるわけですが、raiseやabort関数の結果としてシグナル処理ルーチンを呼び出す場合は、タスク例外を介さずに、直接シグナル処理ルーチンを呼び出すことにします。
というのは、タスク例外処理ルーチンがすべてのタスクに対して定義されているとは限らず、また、特定のタスクの例外処理ルーチンだけを呼び出すのも問題があるからです。しかも、タスク例外処理ルーチンが定義されているかどうかを調べることは(タスク初期化ブロックを直接覗かない限り)できないので、エラー検出ができないことも理由の一つです。
最後に残った課題は、タスク例外禁止状態の操作です。raiseやabort関数の結果としてシグナル処理ルーチンが呼ばれる場合には、タスク例外禁止状態を操作する必要は特にありません。タスク例外処理ルーチンから呼び出す場合が問題ですが、signal(sig, SIG_DFL);さえ実行しておけば、タスク例外禁止状態のままにしておいて、重複して発生したタスク例外を保留しても、規格に反するわけではなさそうなので、深く考えずに放置することにします。
タスク例外禁止状態で、タスク例外処理ルーチンからシグナル処理ルーチンを呼び出した場合、longjmp関数で脱出できなくなりますが、raiseやabort関数の結果としてシグナル処理ルーチンが呼ばれたのでない限り、abort、_Exit、およびsignal関数以外のライブラリ関数を呼び出した場合の動作は未定義なので、特に問題はなさそうです*1。
今回は、思いつくままダラダラと書いてみました。ちょっとわかりにくかったかもしれませんが、次回以降で各関数の実装を行っていきますので、その際に適宜参照していただければと思います。
*1 μITRON 4.0仕様では、タスク例外処理ルーチンからlongjmp関数で脱出することを許していますが、シグナル処理ルーチンが呼び出された以降は、μITRON 4.0仕様ではなく、標準Cライブラリの仕様に従うことになります。
|
| 2006/05/09 23:11|シグナル処理|TB:0|CM:0|▲
|
|
|
コメント
|
|
コメントの投稿
|
|
|
|
|
トラックバック
|
トラックバックURLはこちら
http://libc.blog47.fc2.com/tb.php/53-866b1900
|
|
|
|
|
ホーム
全記事一覧
<< 前の記事
次の記事 >>
|