我正在学习操作系统课程,我们将照常对xv6 OS进行修改。
我们被要求实施惰性内存分配,到目前为止,一切都很好。基本上,当进程调用sbrk()时,我只是增加了它的大小(如果它不是负数),仅此而已。此后,如果我得到一个页面错误,并且它来自用户空间,则仅当不是堆栈保护页面或它属于内核地址空间时,才映射导致错误的页面。
现在是问题了,我们已经进行了一些测试,以检查我们的程序是否运行正常。 这是我无法通过的测试程序:
#include "types.h"
#include "user.h"
int
main(int argc, char *argv[])
{
char* a = sbrk (15000);
fork();
a[500] = 1;
if ((uint)a + 15000 != (uint) sbrk (-15000))
{
printf (1, "sbrk() fail.\n");
exit();
}
if (a != sbrk (0))
{
printf (1, "fail.\n");
exit();
}
if (a != sbrk (15000))
{
printf (1, "fail.\n");
exit();
}
printf (1, "Should print 1: %d.\n", ++a[500]);
a=sbrk (-15000);
a=sbrk(1024*4096*2);
fork();
a[600*4096*2] = 1;
sbrk(-1024*4096*2);
a=sbrk(1024*4096*2);
printf (1, "Should print 1: %d.\n", ++a[600*4096*2]);
exit();
}
我的xv6打印前1张,但随后出现恐慌。恐慌说“重新映射”。检查mappages()函数,我可以看到这种恐慌是由于页面已经被映射并且有人试图重新映射它而引起的,但无法弄清为什么会这样做。我知道调用fork()时,会将父级的页表复制到子级上,因此我修改了复制功能,以免由于内存分配延迟而无法检查该页是否存在并继续复制。
这是蠢货:
int
sys_sbrk(void)
{
int addr;
int n;
if(argint(0, &n) < 0)
return -1;
addr = myproc()->sz;
if(n < 0){
if(growproc(n) == -1) return -1;
}else{
if((addr + n) >= KERNBASE) return -1;
myproc()->sz += n;
}
return addr;
}
这是我处理页面错误的原因:
case T_PGFLT:
if(myproc() == 0){
// In kernel, it must be our mistake.
cprintf("unexpected trap %d from cpu %d eip %x (cr2=0x%x)\n",
tf->trapno, cpuid(), tf->eip, rcr2());
panic("trap");
}
// In user space, assume process misbehaved.
cprintf("pid %d %s: trap %d err %d on cpu %d "
"eip 0x%x addr 0x%x--kill proc\n",
myproc()->pid, myproc()->name, tf->trapno,
tf->err, cpuid(), tf->eip, rcr2());
addr = PGROUNDDOWN(rcr2());
if(addr == myproc()->guardpg){
cprintf("invalid address\n");
myproc()->killed = 1;
break;
}
if(addr >= KERNBASE){
cprintf("invalid address\n");
myproc()->killed = 1;
break;
}
char * marco = kalloc();
if (marco == 0){
cprintf("out of memory\n");
myproc()->killed = 1;
break;
}
memset(marco, 0, PGSIZE);
if(mappages(myproc()->pgdir, (void*)PGROUNDDOWN(rcr2()), PGSIZE, V2P(marco), PTE_W|PTE_U) < 0){
cprintf("Page fault error: Out of memory for the page table.\n");
break;
}
cprintf("Page fault: Mapped page at addr=0x%x.\n", addr);
}