code:sbreak - ikarishinjieva/unixV6-code-analyze-chs GitHub Wiki
- 系统调用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);
3365 if(!u.u_sep)
- n = 传入地址对应的虚拟块号,代表变更后的数据段的末块块号
3366 n =- nseg(u.u_tsize) * 128;
3367 if(n < 0)
- 语句3365 - 3366乍看起来有些匪夷所思,让我们来揭穿它:
- 首先解释一下这两句话的作用: 将n置为 变更后数据段所占的块数
- 接着我们来分析一下它是如何实现的:
3368 n = 0;
3369 d = n - u.u_dsize;
3370 n =+ USIZE+u.u_ssize;
3371 if(estabur(u.u_tsize, u.u_dsize+d, u.u_ssize, u.u_sep))
- d = 新旧数据段长度之差,即长度变更量
- n = 新的进程图像大小(新数据段大小n + ppda区大小USIZE+ 用户栈大小u.u_ssize )
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;
3379 while(n--) {
- a = 新用户栈栈顶指针
- i = 新的进程图像大小
- n = 用户栈大小
3380 copyseg(a-d, a);
3381 a++;
3382 }
3383 expand(i);
- 将用户栈上移 |d| 个字符块
3384 return;
- 将进程图像缩小为变更后的图像大小,放弃多余的内存区
3385
3386 bigger:
- 以下是关于数据段扩大的处理
3387 expand(n);
3388 a = u.u_procp->p_addr + n;
3389 n = u.u_ssize;
3390 while(n--) {
- a = 用户栈底指针
- n = 用户栈大小
3391 a--;
3392 copyseg(a-d, a);
3393 }
3394 while(d--)
- 将进程图像扩大为n(新的图像大小)
- 将原用户栈下移d个字符块,d为数据段增加的块数
3395 clearseg(--a);
3396 }
- 将数据段新增的区域清零
3397 /* -------------------------*/
3398
3399
- (break = 17.)
- sys break; addr