code:xalloc - ikarishinjieva/unixV6-code-analyze-chs GitHub Wiki
4417
4418 /* Attach to a shared text segment.
4419 * If there is no shared text, just return.
4420 * If there is, hook up to it:
4421 * if it is not currently being used, it has to be read
4422 * in from the inode (ip) and established in the swap space.
4423 * If it is being used, but not currently in core,
4424 * a swap has to be done to get it back.
4425 * The full coroutine glory has to be invoked--
4426 * see slp.c-- because if the calling process
4427 * is misplaced in core the text image might not fit.
4428 * Quite possibly the code after "out:" could check to
4429 * see if the text does fit and simply swap it in.
4430 *
4431 * panic: out of swap space
4432 */
4433 xalloc(ip)
4434 int *ip;
4435 {
4436 register struct text *xp;
4437 register *rp, ts;
4438
4439 if(u.u_arg[1] == 0) return;
4440 rp = NULL;
- 若 正文大小为0,函数直接返回
4441 for(xp = &text[0]; xp < &text[NTEXT]; xp++)
4442 if(xp->x_iptr == NULL) {
4443 if(rp == NULL)
4444 rp = xp;
4445 } else
4446 if(xp->x_iptr == ip) {
4447 xp->x_count++;
4448 u.u_procp->p_textp = xp;
4449 goto out;
4450 }
- 找到text数组中 与ip对应的元素xp
- 若找到,则
- 增加 xp 的引用数
- 当前进程 正文控制块指针 指向xp
- 转向4475,进行善后
4451 if((xp=rp) == NULL) panic("out of text");
- 以下开始创建正文块/正文控制块
4452 xp->x_count = 1;
4453 xp->x_ccount = 0;
4454 xp->x_iptr = ip;
4455 ts = ((u.u_arg[1]+63)>>6) & 01777;
4456 xp->x_size = ts;
4457 if((xp->x_daddr = malloc(swapmap, (ts+7)/8)) == NULL)
- 设置xp的参数
- ts ← 正文段 占用 的内存块数(64字节/块)
4458 panic("out of swap space");
4459 expand(USIZE+ts);
- 分配 交换区空间
4460 estabur(0, ts, 0, 0);
- 扩展 进程图像 = PPDA区 + 正文大小的临时区
- 分配的临时区,用来读取代码文件中的代码
- 在4473释放分配的临时区
4461 u.u_count = u.u_arg[1];
- UISA/UISD 地址管理 设置为 数据区大小为ts,其他区为0
- 即 数据区大小从 虚拟地址0开始,大小为ts
- 这里对 UISA/UISD 的修改 需要在exec消除影响,十分不符合函数规范...
4462 u.u_offset[1] = 020;
4463 u.u_base = 0;
4464 readi(ip);
4465 rp = u.u_procp;参考 man a.out
- 从 ip 读取正文到 虚拟地址0
- 文件偏移量 为 020 ,文件正文段从020偏移开始
4466 rp->p_flag =| SLOCK;
4467 swap(xp->x_daddr, rp->p_addr+USIZE, ts, 0);
4468 rp->p_flag =& ~SLOCK;
4469 rp->p_textp = xp;
- 将 刚读入的正文 交换到 盘交换区
- 进程置锁 防止 写盘交换区中 该进程被切换上台
4470 rp = ip;
4471 rp->i_flag =| ITEXT;
4472 rp->i_count++;
- ip 置 ITEXT,防止被写
4473 expand(USIZE);
4474 out:
- 释放 4459 分配的临时区
4475 if(xp->x_ccount == 0) {
4479 u.u_procp->p_flag =| SSWAP;
4480 swtch();
4481 /* no return */
4482 }
4483 xp->x_ccount++;
- 若 正文段 不被 图像在内存中的进程 引用,则将进程交换到盘交换区(诡异的做法,参看说明)
4484 }
4485 /* ------------------------- */
该函数相当诡异,以下做以说明
- 在4449产生分支
- 若 已存在对应的正文控制块,则跳转到4474
- 否则,开始创建 正文块/正文控制块
- 诡异的问题
- 创建的 正文控制块 创建在盘交换区上
- 然后,将现行进程 交换到盘交换区上
- 这个操作看似没有效率,而且很诡异,原因如下
- 进程调度切换程序(sched)上台时 总是先将 正文段交换到内存,再将图像交换到内存
- 若 图像在内存,正文段在交换区,且满足条件rp->x_ccount == 0 (2033),则会引起错误
- 所以需要将 图像交换到盘交换区
- 从4449转过来的情况,也会出现如此情况