KOZOS (23)
昨晩、最後らへんは記憶にない。酒を注入して掘削作業はあまりに微妙ですが今日もそのイキオイで再開。てかリハビリ必要。
リハビリしようと思いつつ DotCloud な記事を見つけたりなんかして (ry
とりあえず
投入したエントリを見つつ誤りを訂正しつつリハビリ。再開なエントリポイントは thread_intr 手続きなようですが、ちょっとだけリハビリなナニを以下にメモ。
まず、起点としては kozos.c の kz_start 手続きの以下の処理
/* 割込みハンドラの登録 */ setintr(SOFTVEC_TYPE_SYSCALL, syscall_intr); /* システム・コール */ setintr(SOFTVEC_TYPE_SOFTERR, softerr_intr); /* ダウン要因発生 */
で、setintr 手続きの定義が以下。
/* 割込みハンドラの登録 */ 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; }
ここで softvec_setintr 手続きが呼ばれてて type な添字と関数ポインタを渡してます。ちなみに softvec_setintr 手続きは interrupt.c で定義されてて以下。
/* ソフトウエア・割込みベクタの設定 */ int softvec_setintr(softvec_type_t type, softvec_handler_t handler) { SOFTVECS[type] = handler; return 0; }
この SOFTVECS が RAM の先頭に配置されてる割り込みベクタテーブル。ただ、handlers という配列もデータセグメントに定義されてて
static kz_handler_t handlers[SOFTVEC_TYPE_NUM]; /* 割込みハンドラ */
setintr 手続きではここに handler が格納されてます。ちょい気持ち悪い。で、softvec_setintr 手続きで割り込みベクタにナニされてるのは何なのかというと thread_intr 手続きで、ここでようやく前回の継続な断点に辿りついた訳です。
thread_intr 手続き
定義が以下。
/* 割込み処理の入口関数 */ 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); /* ここには返ってこない */ }
むむ。とりあえず handlers にセットされたナニを確認してみるか。コメントにある通り、とりあえず syscall_intr 手続きを見てみます。kozos.c にて定義されてて以下。
static void syscall_intr(void) { syscall_proc(current->syscall.type, current->syscall.param); }
あ、ちょっと微妙。掘削開始はここからなのか。
/* システム・コールの処理 */ static void syscall_proc(kz_syscall_type_t type, kz_syscall_param_t *p) { /* * システム・コールを呼び出したスレッドをレディー・キューから * 外した状態で処理関数を呼び出す.このためシステム・コールを * 呼び出したスレッドをそのまま動作継続させたい場合には, * 処理関数の内部で putcurrent() を行う必要がある. */ getcurrent(); call_functions(type, p); }
もしかすると掘ってるかもしれませんが、勘弁してください。
システム・コールの処理
このあたり、昨晩エントリな call graph には反映されてない気がするな。
それは良いとして syscall_proc の中身はコメントにある通り。call_functions 手続きも kozos.c の中で定義されてて以下。
static void call_functions(kz_syscall_type_t type, kz_syscall_param_t *p) { /* システム・コールの実行中にcurrentが書き換わるので注意 */ switch (type) { case KZ_SYSCALL_TYPE_RUN: /* kz_run() */ p->un.run.ret = thread_run(p->un.run.func, p->un.run.name, p->un.run.stacksize, p->un.run.argc, p->un.run.argv); break; case KZ_SYSCALL_TYPE_EXIT: /* kz_exit() */ /* TCBが消去されるので,戻り値を書き込んではいけない */ thread_exit(); break; default: break; } }
あ、これ昨晩エントリで引用してるな。違うかな。そりゃいいのですが呼び出し元の
syscall_proc(current->syscall.type, current->syscall.param);
がポイントなのか。よく考えたらデータ構造完全スルーだったわな。ちなみに TCB の syscall なメンバに云々してるのは kz_syscall 手続きだな。
/* システム・コール呼び出し用ライブラリ関数 */ void kz_syscall(kz_syscall_type_t type, kz_syscall_param_t *param) { current->syscall.type = type; current->syscall.param = param; asm volatile ("trapa #0"); /* トラップ割込み発行 */ }
で
kz_syscall 手続きですよね。これを呼び出してるのが syscall.c に定義されてる手続きな訳です。
kz_thread_id_t kz_run(kz_func_t func, char *name, int stacksize, int argc, char *argv[]) { kz_syscall_param_t param; param.un.run.func = func; param.un.run.name = name; param.un.run.stacksize = stacksize; param.un.run.argc = argc; param.un.run.argv = argv; kz_syscall(KZ_SYSCALL_TYPE_RUN, ¶m); return param.un.run.ret; }
呼び出してるな根拠が以下。
find . -type f -print0 | xargs -0 -e grep -nH -e 'kz_run' ./main.c:9: kz_run(test08_1_main, "command", 0x100, 0, NULL); ./syscall.c:7:kz_thread_id_t kz_run(kz_func_t func, char *name, int stacksize, ./kozos.c:96:/* システム・コールの処理(kz_run():スレッドの起動) */ ./kozos.c:196: case KZ_SYSCALL_TYPE_RUN: /* kz_run() */ ./kozos.h:8:kz_thread_id_t kz_run(kz_func_t func, char *name, int stacksize, Grep finished (matches found) at Wed May 4 21:44:22
おうふ。既視感満点。
これ、明日日中のちゃんとした人間な時間にちゃんと確認する時間を確保しないと駄目だな。kz_run 手続きのあたり。
そもそも始点が昨日エントリの続きでないあたりも微妙だしorz