NetBSDのスケジューラを読んでみるめも6

〆(.. )カリカリッ!! 遂に6回目! sched_lwp_fork()sched_lwp_collect()です。これでsched_4bsd.cで実装している関数は終わります( ´∀`)bグッ!

まずはsched_lwp_fork()です。

    460 void
    461 sched_lwp_fork(struct lwp *l1, struct lwp *l2)
    462 {
    463 
    464 	l2->l_estcpu = l1->l_estcpu;
    465 }

やってることは単純ですね。l1のcpu利用度をl2にコピーするだけです。この関数はsys/kern/kern_lwp.cにあるsched_lwp_fork()から呼ばれます。

    874 	kdtrace_thread_ctor(NULL, l2);
    875 	lwp_initspecific(l2);
    876 	sched_lwp_fork(l1, l2);
    877 	lwp_update_creds(l2);

l2が新しく作っているスレッドになります。
sched_lwp_fork()に関しては関数にあるコメントで簡単に説明されています。

    763 /*
    764  * Create a new LWP within process 'p2', using LWP 'l1' as a template.
    765  * The new LWP is created in state LSIDL and must be set running,
    766  * suspended, or stopped by the caller.
    767  */
    768 int
    769 lwp_create(lwp_t *l1, proc_t *p2, vaddr_t uaddr, int flags,
    770 	   void *stack, size_t stacksize, void (*func)(void *), void *arg,
    771 	   lwp_t **rnewlwpp, int sclass)

プロセP2に新しいlwpを作るためにl1をテンプレートとして使うようですね。 初期状態ではlwpはアイドル状態(LSIDL)にするから呼び出し元で適切な状態に変更してねと書かれてますね。

それでは次にsched_lwp_collect()を見ましょう。

    467 void
    468 sched_lwp_collect(struct lwp *t)
    469 {
    470 	lwp_t *l;
    471 
    472 	/* Absorb estcpu value of collected LWP. */
    473 	l = curlwp;
    474 	lwp_lock(l);
    475 	l->l_estcpu += t->l_estcpu;
    476 	lwp_unlock(l);
    477 }

やってることはこれも単純でカレントのlwpになるlのcpu利用度に引数できたtのcpu利用度を足すだけです。
この関数はsys/kern/kern_lwp.cのlwp_wait()から呼ばれます。

    625 			/*
    626 			 * We're no longer waiting.  Reset the "first waiter"
    627 			 * pointer on the target, in case it was us.
    628 			 */
    629 			l->l_waitingfor = 0;
    630 			l2->l_waiter = 0;
    631 			p->p_nlwpwait--;
    632 			if (departed)
    633 				*departed = l2->l_lid;
    634 			sched_lwp_collect(l2);
    635 

この関数のforの無限ループの中でプロセスAに属する全てのlwpにループでアクセスしつつお互いに待ち合ったことによるデッドロックの検知やスレッドがデタッチされたなどの場合の処理をしてきて、何も待っている状態では無かった時にsched_lwp_collect()を呼ぶようになってます。l2はプロセスAに属するlwpです。

さて、これでsched_4bsd.cと関連する関数の一部は一応読み終わった訳ですがdecay_cpu()、resetpriority()はこのsched_4bsd.cを読む上で重要な位置にあると思います。スケジューラの概要はFreeBSDカーネルの設計と実装でも説明されている(まあ、実装方法はNetBSDFreeBSDで違ってきますが)のであの本と合わせて読むのが良いですね。