minix3のforkめも

んとなく昨日の続きから。だいたいこんな流れ。

do_fork@servers/pm/forkexit.c
  -> sys_fork@lib/syslib/sys_fork.c 
    -> do_fork@kernel/system /do_fork.c

servers/pm/forkexit.c

31 PUBLIC int do_fork()
32 {
中略
94 /* Tell kernel and file system about the (now successful) FORK. */
95 sys_fork(who, child_nr);

lib/syslib/sys_fork.c

1 #include "syslib.h"
2 
3 PUBLIC int sys_fork(parent, child)
4 int parent; /* process doing the fork */
5 int child; /* which proc has been created by the fork */
6 {
7 /* A process has forked. Tell the kernel. */
8 
9 message m;
10 
11 m.PR_PPROC_NR = parent;
12 m.PR_PROC_NR = child;
13 return(_taskcall(SYSTASK, SYS_FORK, &m));
14 }

kernel/system /do_fork.c

17 /*===========================================================================*
18 * do_fork *
19 *===========================================================================*/
20 PUBLIC int do_fork(m_ptr)
21 register message *m_ptr; /* pointer to request message */
22 {
23 /* Handle sys_fork(). PR_PPROC_NR has forked. The child is PR_PROC_NR. */
24 #if (CHIP == INTEL)
25 reg_t old_ldt_sel;
26 #endif
27 register struct proc *rpc; /* child process pointer */
28 struct proc *rpp; /* parent process pointer */
29 int i;
30 
31 rpp = proc_addr(m_ptr->PR_PPROC_NR);
32 rpc = proc_addr(m_ptr->PR_PROC_NR);

それで、サーバからカーネルに渡るデータはforkexit.cの95行目でsys_fork()の呼び出しに使用したwhoとchild_nr。この場合、whoはfork(2)を実行したプロセスなはずで、child_nrはこのような感じで、設定された値。

70 /* Set up the child and its memory map; copy its 'mproc' slot from parent. */
71 child_nr = (int)(rmc - mproc); /* slot number of the child */

ここでrmcは何かというと子プロセス用のmproc構造体で、mprocはプロセスを格納する構造体の配列。
rmcは以下のように最初に見つかった未使用のデータを使う。オペレーティングシステム 第3版時点のコードでは最大プロセス数はNR_PROCSで定義されて、コンパイル時に配列サイズが決定してます。

66 /* Find a slot in 'mproc' for the child process. A slot must exist. */
67 for (rmc = &mproc[0]; rmc mp_flags & IN_USE) == 0) break;
69 

このsys_fork()で渡した引数はカーネルのdo_fork()の中でこんな感じで取得する。

31 rpp = proc_addr(m_ptr->PR_PPROC_NR);
32 rpc = proc_addr(m_ptr->PR_PROC_NR);

PR_PPROC_NRはマクロでwhoとchild_nrにアクセスしていると思ってください。ここはminixのメッセージの構造が絡んでますが、あまり気にしなくても良い部分だし。
proc_addrはマクロでkernel/proc.hで定義。

89 #define proc_addr(n) (pproc_addr + NR_TASKS)[(n)]

これでサーバからカーネルにデータが渡ってる流れが見えた( ´∀`)bグッ!