Я прохожу курс по операционным системам, и мы, как обычно, вносим изменения в ОС xv6.
Нас просили внедрить Lazy Memory Allocation, и пока все хорошо.По сути, когда процесс вызывает sbrk (), я просто увеличиваю его размер (если это не отрицательное число) и все.После этого, если я получаю Page Fault и это из пользовательского пространства, я отображаю страницу, которая вызвала ошибку, только если это не страница защиты стека или она принадлежит адресному пространству ядра.
Теперь вотДело в том, что нам дали несколько тестов, чтобы проверить, работает ли наша программа нормально.Вот тестовая программа, которую я не могу пройти:
#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 () таблица страниц родителя копируется на дочерний, поэтому я изменил функцию копирования, чтобы не проверять наличие страницы, и продолжаю копирование из-за ленивого выделения памяти.
Вот sbrk:
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);
}