xv6的设计trick(不断更新)

1、每个进程通过时钟中断出发trap.c中的

if(proc && proc->state == RUNNING && tf->trapno == T_IRQ0+IRQ_TIMER)
yield();来强制把这个进程置为Runnable状态,yield的实现如下:

acquire(&ptable.lock); //DOC: yieldlock
proc->state = RUNNABLE;
sched();
release(&ptable.lock);

在sched中

swtch(&proc->context, cpu->scheduler); 实现从当前进程的kernel Stack 切换到 CPU中专门负责程序调度的 scheduler Stack,

(gdb) p /x *cpus[0]->scheduler 
$7 = {edi = 0x0, esi = 0x80104ea4, ebx = 0x8, ebp = 0x8010c608, 
eip = 0x80104ab2}

此时,我们在 sched设置断点

(gdb)b proc.c:314

(gdb)s  进入汇编代码

在swtch的汇编代码中,我们将当前进程的esp所指向的内存地址+8 作为新的上下文的esp,然后保存老寄存值,popl加载新的寄存器的值

swtch:

   movl %esp, (%eax)

   movl %edx, %esp

edx 的值就是指向 CPU scheduler的栈底指针的值

 

2、磁盘文件块读写

 

struct buf* bread(uint dev, uint blockno) {
struct buf* b;
b = bget(dev, blockno);
if (!(b.flags & B_VALID)) {
iderw(b);
}
return b;
}

static struct buf* bget(uint dev, uint blockno) {
struct buf* b;
acquire(&bcache.lk);
loop:
for(b = bcache.head.next; b != &bcache.head; b = b->next) {
//if the buf is already in the buffer
if (b->dev == dev && b->blockno == blockno) {
if (!(b.flags & B_BUSY)) {
b.flags &= B_BUSY;
release(&bcache.lk);
return b;
}
sleep(b, &bcache.lk);
goto loop;
}
}
for (b = bcache.head.prev; b != &bcache.head; b = b->next) {
if((b.flags & B_BUSY) == 0 && (b.flags & B_DIRTY) == 0) {
b->dev = dev;
b->blockno = blockno;
b->flags = B_BUSY;
release(&bcache.lk);
return b;
}
}
panic("there isn't any empty buf");
}

posted on 2016-06-10 16:35  Joker_88  阅读(375)  评论(0编辑  收藏  举报

导航