By cszhao1980
System call是提供给user进程的接口,使其可以主动进入内核,完成一些特殊的操作。
多数的sys call的实现很简单,莱昂留给大家分析,我在这里多说几句。
首先是35号系统调用——sleep。这个system call由sslep()函数处理,它的实现比较简单,
我们唯一需要注意的是,它的参数是通过r0传入的。当user进程要休眠一段时间时,会
调用此函数——其参数为醒来的时间。而sslep会用输入时间同tout[ ]数组内记录的下次叫
醒时间作比较,如果早于tout[ ]则更新tout[ ],然后以tout[ ]数组的首地址为睡眠id,调用
sleep(汇编)例程进入睡眠。
显然,所有调用sleep sys call的进程都使用同样的睡眠id,而系统也仅仅记录了第一个要醒来
的时间(即tout数组)。这样,在进行进程唤醒时,所有进程都会醒来。因此,必须在进程醒
来后作一些额外(以确定是否需要再次睡眠)的工作。这样的设计似乎有些低效——莱昂也
提到了这一点。
然后是第35号sys call——nice,用来设置p_nice值,p_nice会用在setpri()那个古怪的算法里。显然,
用户进程可以通过设置nice来改变自己的优先级,但是根据setpri()的算法来看,其影响是有限的。
还有第43号sys call——times(2955: 1, ×, /* 43 = times */),用来获取与进程相关的6种时间。
0447: int u_utime; /* this process user time */
0448: int u_stime; /* this process system time */
0449: int u_cutime[2]; /* sum of childs' utimes */
0450: int u_cstime[2]; /* sum of childs' stimes */
这个sys call的实现很简单,但其内部调用了suword(0861)——这个汇编小程序指定地址的word拷贝
到前地址空间去,它同莱昂重点分析过的fuword的实现很相似,大家不妨看看,也温习一下莱昂的解析。
最后,来几个稍微复杂些的。
sbreak()——用来调整user data segment空间大小,莱昂书中给出了分析。但如果大家看的够仔细的话,可能
会有这样的疑问:
3371: if(estabur(u.u_tsize, u.u_dsize+d, u.u_ssize, u.u_sep))
3372: return;
……
3383: expand(i);
(1) 为什么先调用了estabur,而后才调用expand呢?
(2) 为什么可以这样做呢?
莱昂在这个问题上保持了自己简洁的风格——对此他仅有短短的一句注释:“3 3 7 1:检查新长
度是否满足对存储段的限制”。莱昂的注释解释了问题1,在他看来问题2不需要回答。
如果您觉得难以理解的话,让咱们复习一下estabur ()和expand()的用法:
estabur()的主要作用是:
(1) 验证输入三个segment的大小的合法性;
(2) 根据输入的user三个segment的大小,设置各个segment的protype地址;
(3) 然后,调用sureg()——此函数会根据segment的protype地址、私有空间首地址
进行计算,并设置各个user地址register。
expand()的作用:
(1) 调整data地址空间大小——如果需要新分配空间,则还需要将原有的内
容拷贝到新空间去,并重新设置进程的私有空间地址;
(2) 调用sureg()设置各个user地址register。
您一定要注意:protype地址是相对于进程user私有空间的偏移位置。
因此,调用estabur()后会有两个结果:
(1) 正确设置了protype地址;
(2) (可能)错误设置了user address register。
但是,其后的expand()调用会修正这一错误——因此,“先调用estabur,而后才调用expand”是可行的。
很遗憾,我们现在还不讨论“exec”系统调用,要对它进行分析还需要我们积累更多的知识。
博客地址:http://blog.csdn.net/cszhao1980
博客专栏地址:http://blog.csdn.net/column/details/lions-unix.html