(第36回)割り込みに優先度をつける(前編)

2009/01/21

あなたは 人目のお客様です.

前回までで割り込みとタイマ周りをすっきりさせることができたので, いよいよ割り込みに優先度をつけて,リアルタイム性をさらに高めたい.

まず割り込みの優先度についてなのだけど,やりたいことは, ある割り込みを受けてあるスレッドが動作可能になったときに, 特定の割り込みをマスクすることで,優先度の低い割り込みに割り込まれない ようにすることだ.

優先度の低い割り込みが発生したときに,(たとえスレッドが切り替わらないにしても) 割り込みハンドラが呼ばれてしまっては,結局はもともと動いていた(もっと優先度の 高い)スレッドの処理が待たされてしまう.なので割り込みをマスクすることで, 優先度の低い割り込みを完全に停止させなければならない.

結局のところ,スレッドのディスパッチ時に割り込みマスクされるような機能を追加 することで,割り込みに優先度をもたせてリアルタイム性を確保することができる.

割り込みのマスクは,OSのカーネルが行う必要がある. というのはスレッドのディスパッチ直前(もしくはディスパッチと同時)に, そのスレッドの優先度に応じて割り込みマスクをかける必要があるからだ.

で,KOZOSでの割り込みのマスクのしかたなのだけど,現在,割り込みまわりは extintr スレッドが管理している.なので手っ取り早く考えつくのは,スレッドの ディスパッチ前に extintr に割り込みマスクを行ってもらうという方法だ. 具体的には,KOZOS がスケジューリングの後,スレッドをディスパッチする前に extintr スレッドに(カーネル内部から)依頼メッセージを投げて,さらに extintr を いったんディスパッチして,extintr スレッドに割り込みマスク処理をしてもらう ようにする.(カーネル内部からメッセージを投げるには,メッセージ送信関数である thread_send()を直接呼べばよい)

でもこの方法はダメ.というのは,extintr スレッドに依頼して割り込みマスクをして もらった後にスケジューリングして本来のスレッドをディスパッチしようとするが, ここでまた extintr への依頼が発生してしまい,無限ループになってしまうからだ. これを防ぐためには,2度目は extintr にメッセージを投げないようになんらかの 対処をする必要があるが,これはちょっとめんどいし,多重に割り込みがかかった 場合になんかよくわからんことになりそうな気がする.

もうひとつの方法は,extintr が行っている割り込みまわりの処理をKOZOSのカーネルに 持っていき,カーネルにやらせるというものだ. 現状では各スレッドは extintr にメッセージを投げて割り込み処理を依頼しているが, これらのサービスはカーネルがシステムコールとして実装することになる. 割り込みまわりはすべてカーネルの管理になるので,ディスパッチ前の割り込みマスク 処理も容易だ.

で,ふつうの組み込みOSはそーいう作りになっている思うのだけど,KOZOSはなるべく サービスをスレッド化して,カーネル内部はすっきりさせていきたいという考えが ある.実際に割り込みまわりのサービスも extintr スレッドが行っているし,前回は タイマサービスもスレッド化している(まあこれは,リアルタイム性の無い部分を外に 切り出す,という意味も強いのだが).

ということで,割り込みまわりの管理とサービスは extintr に任せたまま, スレッドのディスパッチ前には割り込みマスクをかけるような実装にしたい. いろいろ考えたのだが,こんな実装はどうだろうか.

ということで,まずは準備として kz_precall() システムコールを追加してみた. ソースは以下のような感じ.

(2009/04/10 ライセンスに関する文書として,KL-01とLICENSEを追加. 詳しくは第43回を参照)

修正内容は簡単で,スレッド構造体に関数ポインタ保存用の precall というメンバを 追加し,kz_precall システムコールで設定,さらにディスパッチ前に関数を呼ぶような 処理を入れているだけ.

ちなみに thread.c:thread_intrvec() でのスケジューリング処理の直後にコメントが あるように,KOZOSではシグナルのとりこぼしを防ぐために,ディスパッチ前に一瞬だけ シグナルマスクを開けている.これは setcontext() でコンテキストが切り替わるため にシグナルが失われてしまうことが原因(このため実ハードウエア上で動作させるなら ば,この処理は不要だろう)なのだけど,precall の実行はこの蓋開けの前に行う必要が ある.蓋開け後だと,precall によるマスク処理中に割り込みが入ってきたときに, なんかわけのわからんことになる気がするし,蓋開け前でマスク処理の設定をして, 蓋開けによって割り込みが入ったとしても,再度スケジューリングが行われて必要に 応じて precall が再度呼ばれてマスクが設定されなおすので,とくに問題は無い.

あー眠い.次回はいよいよ extintr にマスク指定処理を追加して,割り込みを優先度 づけしてみよう.


メールは kozos(アットマーク)kozos.jp まで