POSIX manager の multi task 化に対する考察
[Up]
POSIX manager の multi task 化に対する考察
Apr. 2, 2002 T. Naniwa
I. single task の POSIX manager の欠点
ユーザーアプリケーションからのシステムコールは順に1つずつ実行されるた
め,POSIX manager の処理効率がボトルネックとなる.特に,EXEC システムコー
ルを実行すると,ファイルを読み込み終わるまでユーザーアプリケーションには
実行権限が渡らない.また,POSIX manager は他の要求を受け付けないため,全
てのユーザーアプリケーションの動作が停止してしまうことになっている.
II. multi task 化の利点
multi task 化することで,EXEC などの処理の長いシステムコールを処理して
いる間にも,他のユーザーアプリケーションからのシステムコールが処理できる.
そのため,ユーザーに対する反応性が向上する.
III. multi task 化の限界
POSIX manager 内部での処理が高速化される訳ではなく,また,タスクスイッ
チを起こすポイントも限られているため,manager の性能そのものがボトルネッ
クになることが考えられる.この場合は,現在の manager を memory manager
と file manager に分離するなどの改造が必要となるだろう.
IV. 実装にあって注意すべき点
IV-1. スタックの作成とページテーブルについて.
POSIX manager 上で cre_tsk を実行すると,メモリイメージを共有しながら,
異なる kernel 領域のスタックを持つ新しい task が生成される.POSIX
manager は固有のアドレス空間を持ち,更に特権レベル 3 で動作しているので,
現状では kernel 領域とは別に固有のスタック領域を確保する必要がある.
一方,ページテーブルは heap 領域までのエントリは共有しながら,スタック
領域だけ独立なメモリを割り当てた形のものを用意する必要がある.これは,内
部で kernlib の malloc を呼び出しているためである.
ページテーブルに対する処理を省略するには,メッセージを受ける度に子タス
クを生成し,処理が終了したところでそのタスクも終了させる方法があるが,タ
スクの起動と終了のコストを考えるとこれはあまり得策でないと思われる.
スタックを kernel 領域に持つことにすれば,全く同じページテーブルをタス
ク間で共有することができる.これは cre_tsk/new_tsk を呼び出す際に,引数
の pk_ctsk->addrmap に親タスクの cr3 レジスタの内容を保存しておくこと
で実現できる.ただし,この場合は POSIX manager の特権レベルを変更する必
要がある.
config.tab には現在は使用していないが server というタイプがあるので,
これを活用することで,新たな特権レベルと実行状態を持ったタスクを用意する
ことは可能である.
尚,新しい task のエントリーは,受信用メッセージバッファに対して recv
を実行し,受信後システムコールの呼び出しを行うような関数であれば良い.
IV-2. 排他制御するべきデータ構造の確認
POSIX manager はスケジューラによって実行権限を他の task に横取りされる
ことはないので,異なる manager task に実行権限が移るのは,システムコール
の実行中に他の task にメッセージを送信した場合のみである.
考えられるのは,デバイスに対して open, read, write, close 等のメッセー
ジを送信する部分であり,その際に使用する大域変数が排他制御の対象となる.
まずは,システムコールの中から直接デバイスにメッセージを送る部分を拾い出
し,依存する大域変数を調査する.
POSIX manaber 中で利用されている一時的(局所的)でない変数
/* POSIX/manager */
□ static ID log_port;
□ static ID dev_recv;
これらの変数は log.c の中で局所的に宣言されているが,manager の存在中
は唯一の変数として使用される.これは,デバッグメッセージの出力に使われる.
初期化の際に設定される変数のため,排他制御する必要は無い.
□ static ID request_port;
request.c の中で,POSIX manager の受信用ポートを保持するために使用され
る.
初期化の際に設定されるので,排他制御する必要は無い.
/* POSIX/manager */
□ struct fs fs_buf[], *free_fs, *rootfs;
これらはファイルシステムの管理に関係する変数である.rootfs は起動時に
設定された後は変更されることは無い.free_fs は mount/umount システムコー
ルの結果によって変更される.fs_buf[] の内容の更新は,free_fs の先頭にあ
る要素に対して行われる.
free_fs は alloc_fs/dealloc_fs を通して更新される.これらは disk アク
セスを伴う mount/umount システムコールの前後に呼び出される.多重に呼び出
されても問題は発生しないため,排他制御の必要は無い.
□ struct inode inode_buf[], *free_inode, *rootfile;
これらはファイルの管理に関係する変数である.rootfile は起動時に設定さ
れた後は変更されることは無い.free_inode はファイルの割り当て,開放を伴
うシステムコールの結果によって変更される.
free_inode に関する操作の間にタスクスイッチは起こらないため,排他制御
の必要は無い.
□ struct special_file special_file_table[];
ファイルの major/minor 番号と,manager の PORT の対応を管理する.最初
に利用された内容が更新される.
万一同時に更新が起こっても,代入されるのは同一の情報であるため,排他制
御する必要は無い.
□ struct proc proc_table[MAX_PROCESS], free_proc, tail_proc, run_proc;
プロセスの,生成,終了によって更新される.run_proc は使用されていない.
free_proc, tail_proc の修正の間にタスクスイッチが生じることは無いので,
排他制御は必要無い.
□ struct file file_buf[], *free_file;
これらの変数は,現在は使用されていない.
□ 関数内部の static 変数.
buf[] などという名称で file や page のバッファが static 変数として宣言
されている場合がある,POSIX manager のスタックに余裕があるのであれば,自
動変数にしてしまえば問題は生じない.
/* POSIX/manager/sfs */
□ extern struct fsops sfs_fsops;
□ extern struct iops sfs_iops;
これらの変数はファイルシステムを構成する関数群を保持するための配列で,
定数配列である.
□ cache 関係のデータ
static int CACHE_SIZE = 2048;
/*static SFS_BLOCK_CACHE *cache_data;*/
static SFS_BLOCK_CACHE cache_data[CACHE_SIZE];
static short int cache_head;
static short int hash_table[HASH_SIZE + 1];
ディスクブロックの読み書きに関連して更新される.キャッシュの内容をディ
スクに読みに行く間に,別のブロックへのアクセスが発生する.同じブロックに
連続して読み出しの要求が行われる可能性があり,その場合には問題が発生する
恐れが高い.
/* ITRON/kernlib */
□ extern ER sys_errno;
外部プロセスとエラーコードを共有する目的で作られた変数だが,現在はまと
もに機能していない.マルチタスク状況下では使用できないので,そのまま無視
することにする.
IV-3. OS 起動時の server task の起動について.
init の daemon ワードで server task を起動すると,すぐさま init に制御
が戻り,次々と daemon が起動されることになる.この場合,ディスクデバイス
へのアクセスがバラバラに発生して読み取り効率が著しく悪化することが考えら
れる.
init に sleep を実装したので,daemon ワードの呼び出しの間に適当な長さ
の sleep を挟むことで対処することを考えている.起動に多少無駄な時間が生
じることになるが,解決策としては最も手軽な方法だと思われる.