UNIX 7th code reading - process switch (context switch)

はじめに

前回のエントリで、UNIX 6thと7thでprocess switch(context switch)の仕様が違うかもしれないという話をしました。

今回はそれを明らかにするために、7thのsave( )とresume( )を確認していきます。

newproc( )で生成したプロセスがswtch( )で選択されたときの流れを見ていきます。

6thでは

6thについては以前解説を書いたので、そちらを参考にしてください。

7thでは

save

まずはnewproc( )の中でsave( )を呼んでいる箇所を確認します。

http://www.tamacom.com/tour/kernel/unix/S/96.html

 503         if (save(u.u_ssav)) {
 504                 sureg();
 505                 return(1);
 506         }

u.u_ssavを引数にsave( )を呼んでいます。u_ssavの型はlabel_tです。label_tがどういうものかを確認すると、int6個分の配列であることがわかります。

http://www.tamacom.com/tour/kernel/unix/S/68.html

   5 typedef int             label_t[6];     /* program status */

save( )に制御が移ったときのスタックの状態は以下のようになります。なぜこうなるかは6thについてまとめたエントリを参考にしてください。7thでも話は変わっていないはずです。

sp stack
 
sp -> return address(PC)
u.u_ssav(argument)
 

続いてsave( )の中のロジックを見ていきます。

http://www.tamacom.com/tour/kernel/unix/S/1.html

 713 .globl  _save
 714 _save:
 715         mov     (sp)+,r1
 716         mov     (sp),r0
 717         mov     r2,(r0)+
 718         mov     r3,(r0)+
 719         mov     r4,(r0)+
 720         mov     r5,(r0)+
 721         mov     sp,(r0)+
 722         mov     r1,(r0)+
 723         clr     r0
 724         jmp     (r1)

最初の2命令でsaveから戻る先のアドレス(return address)をr1に格納し、u.u_ssavのポインタをr0に格納しています。

続いてr2からr6(sp)までをu.u_ssav配列に格納していき、最後尾にr1を格納しています。表で表すとこうなります。

index u.u_ssav
0 r2
1 r3
2 r4
3 r5
4 r6(sp)
5 r1(return address)

その後r0をクリアし、jmp命令でr1(return address)に飛ぶことで、save( )呼び出し元に戻ります。r0が返り値となるので、呼び出し元には0が返ります。

呼び出し元であるnewproc( )を再確認します。

 503         if (save(u.u_ssav)) {
 504                 sureg();
 505                 return(1);
 506         }

save( )から0が返ってくるので、if文の条件式は偽となり、507行目以降の処理を継続します。newproc( )を呼び出したのはプロセスを新規に作成しようとしている親プロセスですので、新規プロセスの初期設定を継続するというわけです。

resume

続いて、swtch( )で新たなプロセスが選択された後の処理を確認します。

http://www.tamacom.com/tour/kernel/unix/S/96.html#L347

 416         n = p->p_flag&SSWAP;
 417         p->p_flag &= ~SSWAP;
 418         resume(p->p_addr, n? u.u_ssav: u.u_rsav);

returnではなく、resume( )を使っているのがわかります。newproc( )で生成されたプロセスにはSSWAPフラグが立つので

メモ:newproc( )で立てられたSSWAPフラグは上記417行目で落とされる?

 528         rpp->p_flag |= SSWAP;

resume( )の第二引数にはu.u_ssavのポインタが渡ります。resume( )に制御が移ったときのスタックの状態は以下のようになります。

sp stack
 
sp -> return address(PC)
p->p_addr(argument)
u.u_ssav(argument)
 

resume( )のロジックを確認していきます。

http://www.tamacom.com/tour/kernel/unix/S/1.html

 726 .globl  _resume
 727 _resume:
 728         mov     2(sp),r0                / new process
 729         mov     4(sp),r1                / new stack
 730         bis     $HIPRI,PS
 731         mov     r0,KISA6                / In new process
 732         mov     (r1)+,r2
 733         mov     (r1)+,r3
 734         mov     (r1)+,r4
 735         mov     (r1)+,r5
 736         mov     (r1)+,sp
 737         mov     $1,r0
 738         bic     $HIPRI,PS
 739         jmp     *(r1)+

最初の2命令で、p->p_addrをr0に、u.u_ssavをr1に格納しています。

続いて割り込みを防ぐためにプロセッサ優先度を上げた後に、r0(p->p_addr)をKISA6(7番目のPAR)を格納します。この時点でu構造体が新たに選択されたプロセスの領域を指すようになります。このあたりは6thのときのまとめを参考にしてください。

u構造体が選択されたプロセスの領域を指すようになるということは、u.u_ssavを使ってsave( )で格納した情報を取得できるようになったということです。

save( )でs.u_ssavに格納したr2-6を復帰させます。r0に1を格納させた後にプロセッサ優先度を元に戻します。この時点でのu.u_ssav, registerの状態を表すと以下のようになります。

index u.u_ssav r
0 r2 -> r2
1 r3 -> r3
2 r4 -> r4
3 r5 -> r5
4 r6 -> r6
r1-> 5 r1(return address)    
r value
r0 1

jmp命令でresume( )を抜けます。オペランドは*(r1)+です。この時点でr1はu.u_ssavの最後尾を指していて、そこにはsave( )を実行したときのreturn addressが格納されています。返り値であるr0には1が格納されているので、save( )を実行した箇所にreturn 1で戻るというわけです。

newproc( )のsave( )実行箇所を再度確認します。

 503         if (save(u.u_ssav)) {
 504                 sureg();
 505                 return(1);
 506         }

return 1で戻ってくるので、if文の条件式が真となり、sureg( )を実行してPAR, PDRを設定しなおしてから、return 1でnewproc( )の呼び出し元に戻ります。

6thと7thの違い

7thではprocess switch(context switch)処理がだいぶシンプルになった感じがします。

6thではreturnの先を無理やり制御しようとしていたのに対し、7thではreturnの変わりにresume( )を使っているのが大きな違いです。

前回のエントリで載せた絵を再掲しておきます。


終わりに

気になっていた7thのprocess switch(context swtich)が確認できました。newproc( )でSSWAPする話やu.u_ssav, u.u_rsavの使い分けなど、細かな部分はまだ理解できていませんが、プロセス周りを確認するときに見ていこうと思います。

次からはファイルシステム周りを見ていく予定です。