code:sbreak - ikarishinjieva/unixV6-code-analyze-chs GitHub Wiki

Source

  • 系统调用break的执行函数
  • 用于使数据段长度变更
  • 通过u.u_arg[0]传入1个参数,它是一个未经地址转换的虚拟地址,指向变更后数据段的末块

3350

3351 /* break system call.

3352  * -- bad planning: "break" is a dirty word in C.

3353  */

3354 sbreak()

3356     register a, n, d;

3357     int i;

3358

3359     /* set n to new data size

3360     * set d to new-old

3361     * set n to new total size

3362     */

3363

3364     n = (((u.u_arg[0]+63)>>6) & 01777);

  • n = 传入地址对应的虚拟块号,代表变更后的数据段的末块块号
3365     if(!u.u_sep)

3366           n =- nseg(u.u_tsize) * 128;

  • 语句3365 - 3366乍看起来有些匪夷所思,让我们来揭穿它:
  • 首先解释一下这两句话的作用: 将n置为 变更后数据段所占的块数
  • 接着我们来分析一下它是如何实现的:
    • 3365:u.u_sep = 0, 表明进程的共享正文段和数据段以及用户栈公用一个地址映照表,参看内存管理.由于对于pdp11/40而言u.u_sep恒定为0,因此该判断成立
    • 接下来是神奇的3366行:
    • 前面提到我们的目的是要将n变为数据段所占的块数,那么我们离这个目标有多远呢?
    • 我们通过下图以一个例子来说明:

  • 相信这幅图片已经足以说明一切问题
  • 请特别注意途中彩色的字,并仔细理解其含义
  • 如果你还有疑惑,那么请联系UNIX内存管理以及pdp11内存管理加以理解
3367     if(n < 0)

3368           n = 0;

3369     d = n - u.u_dsize;

3370     n =+ USIZE+u.u_ssize;

  • d = 新旧数据段长度之差,即长度变更量
  • n = 新的进程图像大小(新数据段大小n + ppda区大小USIZE+ 用户栈大小u.u_ssize )
3371     if(estabur(u.u_tsize, u.u_dsize+d, u.u_ssize, u.u_sep))

3372           return;

  • 通过设置相对地址映照的方式检查进程大小是否越界
  • 若越界则直接返回
3373     u.u_dsize =+ d;
  • 若没有越界,则将数据段的大小加上长度变更量
3374     if(d > 0)

3375           goto bigger;

  • 若数据段变大,跳至3386行
  • 以下是数据段不变或变小的处理
3376     a = u.u_procp->p_addr + n - u.u_ssize;

3377     i = n;

3378     n = u.u_ssize;

  • a = 新用户栈栈顶指针
  • i = 新的进程图像大小
  • n = 用户栈大小
3379     while(n--) {

3380           copyseg(a-d, a);

3381           a++;

3382     }

  • 将用户栈上移 |d| 个字符块
3383     expand(i);
  • 将进程图像缩小为变更后的图像大小,放弃多余的内存区
3384     return;

3385

  • 以下是关于数据段扩大的处理
3386 bigger:

3387     expand(n);

3388     a = u.u_procp->p_addr + n;

3389     n = u.u_ssize;

  • a = 用户栈底指针
  • n = 用户栈大小
3390     while(n--) {

3391           a--;

3392           copyseg(a-d, a);

3393     }

  • 将进程图像扩大为n(新的图像大小)
  • 将原用户栈下移d个字符块,d为数据段增加的块数
3394     while(d--)

3395     clearseg(--a);

  • 将数据段新增的区域清零
3396 }

3397 /* -------------------------*/

3398

3399

Ref

Param

(break = 17.)
sys break; addr
⚠️ **GitHub.com Fallback** ⚠️