(莱昂氏unix源代码分析导读-34)You are not expected to understand this

 

                                                                  By cszhao1980

本章将探讨unix v6代码中最微妙的部分,即著名的注释:“ You are not expected to understand this”。

 

2178: swtch()

2179: {

2180:     static struct proc *p;

2181:     register i, n;

2182:     register struct proc *rp;

          ……

2228:     retu(rp->p_addr);

2229:     sureg();

2230: /*

2231: * If the new process paused because it was

2232: * swapped out, set the stack level to the last call

2233: * to savu(u_ssav). This means that the return

2234: * which is executed immediately after the call to aretu

2235: * actually returns from the last routine which did

2236: * the savu.

2237: *

2238: * You are not expected to understand this.

2239: */

2240:     if(rp->p_flag&SSWAP) {

2241:         rp->p_flag =& ~SSWAP;

2242:         aretu(u.u_ssav);

2243:     }

2244: /* The value returned here has many subtle implications.

2245: * See the newproc comments.

2246: */

2247:     return(1);

2248: }

 

相关代码仅有三行,逻辑非常简单:

(1)         swtch()退出之前,会检查进程的SSWAP标志;

(2)         如该标志置位,则清理该标志,然后调用aretu(u.u_ssav)

 

首先看一下aretu(),这个函数与retu()的作用类似:

(1)         使用参数指向的内容更新spr5

(2)         不同的是,aretu()不会更新KISA6,即不会进行进程切换。

 

看起来,swtch()神秘代码的作用是调整spr5,以使其在return时跳到另外的地

方——即savu(u.u_ssav);的调用者的调用者。

 

接下来,让我们看看,会设置SSWAP标志的几种情况:

(1)         expand函数;

2268: expand(newsize)

2269: {

2270:     int i, n;

……

2281:     savu(u.u_rsav);

2282:     a2 = malloc(coremap, newsize);

2283:     if(a2 == NULL) {

2284:         savu(u.u_ssav);

2285:         xswap(p, 1, n);

2286:         p->p_flag =| SSWAP;

2287:         swtch();

2288:         /* no return */

2289:     }

……

2296: }

 

(2)         xalloc函数;

4433: xalloc(ip)

4434: int *ip;

4435: {

……
4474: out:

4475:     if(xp->x_ccount == 0) {

4476:         savu(u.u_rsav);

4477:         savu(u.u_ssav);

4478:         xswap(u.u_procp, 1, 0);

4479:         u.u_procp->p_flag =| SSWAP;

4480:         swtch();

4481:        /* no return */

4482:      }

4483: xp->x_ccount++;

4484: }

 

(3)         newproc函数;

1826: newproc()

1827: {

1828:     int a1, a2;

……

1896:     a2 = malloc(coremap, n);

1897:    /*

1898:     * If there is not enough core for the

1899:     * new process, swap out the current process to generate the

1900:     * copy.

1901:     */

1902:     if(a2 == NULL) {

1903:         rip->p_stat = SIDL;

1904:         rpp->p_addr = a1;

1905:         savu(u.u_ssav);

1906:         xswap(rpp, 0, 0);

1907:         rpp->p_flag =| SSWAP;

1908:         rip->p_stat = SRUN;

1909:      } else {

……

1919: }

 

呵呵,这几个函数都是我们的老朋友,只是当初都跳过了SWAP相关的部分。现在,

是了解他们的时候了。总得来说,设置SSWAP标志发生在当前进程的coremap资源得

不到满足的情况下:

(1)         expand来说,malloc更大的coremap失败;

 

(2)         xalloc来说,要“连接”的text segment的活动计数为0(总计数不为0),即该

                  text segment已经被swap out。于是,当前进程无法执行,则将当前进程换出;

 

(3)         newproc来说,无法为新进程申请足够的core空间,于是需要将生成的新进程换出。

 

不但如此,这三个函数都在xswap之前调用了savu(u.u_ssav)——这使得swtch()函数的第2242行

“  aretu(u.u_ssav)”造成的影响是,当swtch()返回时,将直接返回到这三个函数的调用者。

 

下面,我将以expand的情况为例,来讲解其中的原因。

首先,还记得前面在讲解expand时提到的那个小技巧末?即使用xswap的第三个参数(old size),

在换出时,只换出有效的内容。如果您足够细心,您还会注意到,expand()函数换出内存image时,

swap空间中申请的是newsize的大小。这样做的结果是,当调度进程将该进程换入时,会申请

newsize大小的core空间,即实现了expand函数的调用初衷。

 

接下来,我们看一下expand函数正常返回时(即core空间足够时)的逻辑路径,相比较core空间

不足的情况,多了一些代码,如下所示:

2283:     if(a2 == NULL) {

          …                //core空间不足时

2289:     }                     

                            //core空间足够时

2290:     p->p_addr = a2;        // 重新设置u地址

2291:     for(i=0; i<n; i++)       //拷贝原有u地址空间的内容

2292:         copyseg(a1+i, a2++);

2293:     mfree(coremap, n, a1);   //释放原有u空间

2294:     retu(p->p_addr);        //KISA6指向新u空间

2295:     sureg();               //设置user寄存器          

 

expand()申请core空间失败的情况下,这些代码所做的事情会被其他的程序完成:

(1)         swap out时,会free掉原有u空间;

(2)         swap in时,调度进程会重设KISA6user寄存器;而且,调度进程会

                   申请newsizecore空间,并将swap空间的image拷贝到core中。

 

因此,进程在恢复运行时,应该直接跳到expand()函数之后运行——就好像它

刚刚成功的执行了一个expand一样。而这正是由神秘的“You are not expected

 to understand this”代码所完成的。

 

博客地址:http://blog.csdn.net/cszhao1980

博客专栏地址:http://blog.csdn.net/column/details/lions-unix.html

你可能感兴趣的:((莱昂氏unix源代码分析导读-34)You are not expected to understand this)