KOZOS (20)
os 側の始点としては kozos.c で定義されてる kz_start 手続きになるのかどうなのか。
呼び出し側の記述が以下。
/* OSの動作開始 */ kz_start(start_threads, "start", 0x100, 0, NULL); /* ここには戻ってこない */
定義を順に見てみます。
void kz_start(kz_func_t func, char *name, int stacksize, int argc, char *argv[]) { /* * 以降で呼び出すスレッド関連のライブラリ関数の内部で current を * 見ている場合があるので,current を NULL に初期化しておく. */ current = NULL; readyque.head = readyque.tail = NULL; memset(threads, 0, sizeof(threads)); memset(handlers, 0, sizeof(handlers));
このあたりは大事なデータ構造の初期化になるのかな。定義が以下あたり (kozos.c)
/* スレッドのレディー・キュー */ static struct { kz_thread *head; kz_thread *tail; } readyque; static kz_thread *current; /* カレント・スレッド */ static kz_thread threads[THREAD_NUM]; /* タスク・コントロール・ブロック */ static kz_handler_t handlers[SOFTVEC_TYPE_NUM]; /* 割込みハンドラ */
で、初期化の一環として以下な手続きを呼び出しているのですが、
/* 割込みハンドラの登録 */ setintr(SOFTVEC_TYPE_SYSCALL, syscall_intr); /* システム・コール */ setintr(SOFTVEC_TYPE_SOFTERR, softerr_intr); /* ダウン要因発生 */
この setintr 手続きの定義の中で宣言されてる手続き thread_intr って何? って思ったのですが
static int setintr(softvec_type_t type, kz_handler_t handler) { static void thread_intr(softvec_type_t type, unsigned long sp); /* * 割込みを受け付けるために,ソフトウエア・割込みベクタに * OSの割込み処理の入口となる関数を登録する. */ softvec_setintr(type, thread_intr); handlers[type] = handler; /* OS側から呼び出す割込みハンドラを登録 */ return 0; }
これ、kozos.c の後ろで定義されてますね。なんでこんな書き方になってるのか、は後々分かるのかどうなのか。
とりあえず入口を定義しといて、入口の thread_intr 手続きでは handlers[type] が NULL でなければ呼び出して云々な処理が記述されてます。コメントにある SOFTVEC_TYPE_SYSCALL あるいは SOFTVEC_TYPE_SOFTERR 以外のケイスというのはどれにあたるのかな。
thread_intr 手続きの定義は kozos.c にて以下。
/* 割込み処理の入口関数 */ static void thread_intr(softvec_type_t type, unsigned long sp) { /* カレント・スレッドのコンテキストを保存する */ current->context.sp = sp; /* * 割込みごとの処理を実行する. * SOFTVEC_TYPE_SYSCALL, SOFTVEC_TYPE_SOFTERR の場合は * syscall_intr(), softerr_intr() がハンドラに登録されているので, * それらが実行される. */ if (handlers[type]) handlers[type](); schedule(); /* スレッドのスケジューリング */ /* * スレッドのディスパッチ * (dispatch()関数の本体はstartup.sにあり,アセンブラで記述されている) */ dispatch(¤t->context); /* ここには返ってこない */ }
あ、ハンドラ呼び出した後に再スケジュールして、、ってヤッてますね。先に登録された処理云々を確認しといた方が良いはずなのでそちらを確認。
と思ったのですが
kozos.c のあたりをまるっと確認した方が良さげなカンジがしてきました。ええとテキストによるとここでスレッド管理とシステム・コールの受け付け、割り込み処理を行なっているとのこと。
先頭部分で肝心なデータ構造が定義されてます。
- kz_context 型
- スレッド・コンテキストとのこと (コメントより)
- 属性としてスタックポインタを持っている模様
- kz_thread 型
- 属性として kz_context 型の変数を持っている
- リンクリストな next ポインタな属性を持っている
- readyque という変数
- 属性として kz_thread 型ポインタの head と tail を保持
- kz_thread は双方向リストではないな
- なんのためにケツのポインタ持ってるのかな
あら?
ちょっと随分 jmp しちゃってますが dispatch が何なのか、がワケワカになってるな。ちなみに dispatch が呼び出されてるのは
- thread_intr 手続き
- コメントによれば_割り込み処理の入口関数_とのこと
- kz_start 手続き
- これはエントリな手続きですな
ええと渡されたポインタからレジスタを復帰してるのは分かるんですが、current->context というのは一体何だったか、ってまだ読んでないのですがorz
あ、kz_start 手続きにて以下な記述を発見。
/* 最初のスレッドを起動 */ dispatch(¤t->context); /* ここには返ってこない */
dispatch 手続きのケツにある
rte
はプログラム・カウンタと CCR の値をスタックから復旧とある。このあたり理解不足満点なんですが、今日はもう限界か。