(注意)このブログは本家のほうの文章部分のみの転載です.ソースコードの配布,画像などについては本家のほうを参照してください.文章中のリンク先は面倒なのですべて本家のほうに変換してしまっているのでご注意ください.

いよいよ,割り込みに優先度づけをすることで,KOZOSを完全にリアルタイムOS化する.まあ僕的に「完全なリアルタイムOS」ってなものがどんなものかまだいまいちよく理解できていないところがあるのだが,とりあえずこれでリアルタイムOSと言えるのではないか...というところまで持っていってみよう.

割り込みの優先度づけなのだけど,前回実装した kz_precall() システムコールにより,スレッドのディスパッチの直前に特定の関数が呼ばれるように登録しておいて,で,その関数内部で優先度の低い割り込みをマスクすることで実装する.これにより,ある割り込みが入ってその処理スレッドが動作している最中に,別の優先度が低い割り込みが入ることはなくなり,割り込みに優先度をつけて,完全にリアルタイムOS化することができる.

実はこの優先度づけの実装の前段階として,第36回,第37回で準備を行ってきたので,今回の実装はそれほど難しくはない.ソースは以下のような感じ.

変更点については diff.txt を参照してほしいのだが,まず,割り込みのマスク/マスク解除用のサービス関数として mask, unmask という関数ポインタをstruct interrupts に追加している.これはそれぞれ割り込みをマスク/マスク解除するためのサービス関数になる.で,タイマ割り込みとコンソール割り込み用のマスク/マスク解除関数として,timer_mask(), timer_unmask(), cons_mask(), cons_unmask() を追加している.内容は,制御ソケットを使って子プロセスに割り込みのマスク要求を出すだけだ.これはKOZOSを実機で動作させる場合には,割り込みマスクレジスタを直接操作するという実装になる.

さらに,kz_precall() で登録する割り込みマスク処理関数として,preproc() を追加している.内容は,自分より優先度の高い割り込みは unmask() を呼び出してマスク解除し,優先度の低い割り込みは mask() を呼び出して割り込みマスクをしているだけだ.

あと kz_precall() によって,スレッドごとにマスク処理関数が呼ばれるようにしてある.extintr の場合は全マスク,その他のスレッドの場合はマスク無しになるように手を入れている.ここまでが extintr.c の修正内容だ.

main.c は,スレッドの優先度を割り込み優先度に合わせて調整した.前回説明したが,現状で利用されている割り込みの優先度は,以下のようになっている.(これは extintr.c の extintr_intr_regist() の呼び出しで決定されている)
  • 優先度0の割り込み ... タイマ割り込みの0番
  • 優先度1の割り込み ... コンソール割り込みの0番
  • 優先度2の割り込み ... タイマ割り込みの1番
で,上から順に clock.c, command.c, timerd.c で利用されている.なので clock スレッドを優先度10,commandスレッドを優先度11,timerdスレッドを優先度12として優先度の順番をそろえた.あとそれ以外のスレッドは割り込みとは関係が無いので,優先度を20番代にして低くしておいた.

thread.c は,kz_precall() でデフォルトの関数を登録できるように改造した.これにより,kz_precall() でディスパッチ前のコールバック関数を登録していないスレッドの場合に,デフォルトのコールバック関数を呼び出させることができる.これは優先度の低い一般スレッドがディスパッチされる際に,すべての割り込みのマスクを解除するために利用する.

最後に,timerd.c をちょろっと修正.

で,動作させてみたところ,とりあえずタイマとコンソールは従来通り動いた.ただ,たまに動作が停止して固まってしまうようなんだよね...うーん原因不明.