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

Source

  • 用于处理"原始"输入/输出操作,即跳过缓存机制,直接在内存与磁盘中进行数据传输
  • 传入4个参数:
    • start : 设备处理I/O请求的函数
    • abp : "特殊缓存块",设备专用于"原始"输入/输出操作的缓存块
    • dev : 设备号
    • rw : 读/写标志位
  • 隐式调用的参数:

5248

5249 /*

5250  * Raw I/O. The arguments are

5251  * The strategy routine for the device

5252  * A buffer, which will always be a special buffer

5253  * header owned exclusively by the device for this purpose

5254  * The device number

5255  * Read/write flag

5256  * Essentially all the work is computing physical addresses

5257  * and validating them.

5258  */

5259 physio(strat, abp, dev, rw)

5260 struct buf *abp;

5261 int (*strat)();

5262 {

5263     register struct buf *bp;

5264     register char *base;

5265     register int nb;

5266     int ts;

5267

5268     bp = abp;

5269     base = u.u_base;

  • base置为I/O传输的内存首地址
5270     /*

5271     * Check odd base, odd count, and address wraparound

5272     */

5273     if (base&01 || u.u_count&01 || base >= base+u.u_count)

5274           goto bad;

  • 若内存起始地址是奇地址(即不是一个字的首地址),或要传输的字节为奇字节,或要传输的字节数不为正
    • 进行出错处理
5275     ts = (u.u_tsize+127) & ~0177;
  • ts置为共享正文段最后一页的下一页的首块块号(即数据段第一页的首块号)
  • 参看Pdp11:内存管理
5276     if (u.u_sep)

5277          ts = 0;

  • 检查指令区和数据区是否分开,对于pdp11/40,u.u_sep恒为0
5278     nb = (base>>6) & 01777;
  • nb = I/O传输的内存起始块号
5279     /*

5280     * Check overlap with text. (ts and nb now

5281     * in 64-byte clicks)

5282     */

5283     if (nb < ts)

5284          goto bad;

  • 若内存起始块号在正文段范围之内,进行出错处理
5285     /*

5286     * Check that transfer is either entirely in the

5287     * data or in the stack: that is, either

5288     * the end is in the data or the start is in the stack

5289     * (remember wraparound was already checked).

5290     */

5291 if ((((base+u.u_count)>>6)&01777) >= ts+u.u_dsize

5292      && nb < 1024-u.u_ssize)

5293           goto bad;

  • 如果要传输的内容横跨数据段和代码段
    • 进行出错处理
5294     spl6();
  • 以下是对"特殊缓存块"的处理,为保持临界资源互斥,故需关中断
5295     while (bp->b_flags&B_BUSY) {

5296           bp->b_flags =| B_WANTED;

5297           sleep(bp, PRIBIO);

5298     }

5299     bp->b_flags = B_BUSY | B_PHYS | rw;

5300     bp->b_dev = dev;

5301     /*

5302     * Compute physical address by simulating

5303     * the segmentation hardware.

5304     */

5305     bp->b_addr = base&077;

5306     base = (u.u_sep? UDSA: UISA)->r[nb>>7] + (nb&0177);

5307     bp->b_addr =+ base<<6;

5308     bp->b_xmem = (base>>10) & 077;

5309     bp->b_blkno = lshift(u.u_offset, -9);

5310     bp->b_wcount = -((u.u_count>>1) & 077777);

5311     bp->b_error = 0;

5312     u.u_procp->p_flag =| SLOCK;

  • 对"特殊缓存块"进行相关赋值,并在最后将当前进程置SLOCK标志
5313     (*strat)(bp);
  • 启动设备I/O处理函数
5314     spl6();
5315     while ((bp->b_flags&B_DONE) == 0)

5316           sleep(bp, PRIBIO);

5317     u.u_procp->p_flag =& ~SLOCK;

5318     if (bp->b_flags&B_WANTED)

5319           wakeup(bp);

5320     spl0();

5321     bp->b_flags =& ~(B_BUSY|B_WANTED);

  • 待"特殊缓存块"I/O结束后,判断是否有B_WANTED标志
    • 若有,则唤醒睡眠在"特殊缓存块"上的进程
  • 开中断
  • 清B_BUSY与B_WANTED标志
5322     u.u_count = (-bp->b_resid)<<1;

5323     geterror(bp);

  • I/O过程中的出错处理
    • 将未能传输的字数赋给u.u_count
    • 对错误进行相关处理
5324     return;

5325 bad:

5326     u.u_error = EFAULT;

5327 }

5328 /* ------------------------- */

|ref =

Caller

⚠️ **GitHub.com Fallback** ⚠️