Неспособность реализовать ленивое распределение памяти - PullRequest
0 голосов
/ 20 декабря 2018

Я прохожу курс по операционным системам, и мы, как обычно, вносим изменения в ОС 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);
  }
...