diff options
| author | Robert Morris <rtm@nephron.lcs.mit.edu> | 2010-08-10 17:08:41 -0400 | 
|---|---|---|
| committer | Robert Morris <rtm@nephron.lcs.mit.edu> | 2010-08-10 17:08:41 -0400 | 
| commit | 83d2db91f75460e1275d67847adec0fca5a9800b (patch) | |
| tree | cc8df8349ca1981e85d8e343dbf365b59f5eabd7 | |
| parent | c4cc10da7ef6d65f0f654445e0af35b8309f16c2 (diff) | |
| download | xv6-labs-83d2db91f75460e1275d67847adec0fca5a9800b.tar.gz xv6-labs-83d2db91f75460e1275d67847adec0fca5a9800b.tar.bz2 xv6-labs-83d2db91f75460e1275d67847adec0fca5a9800b.zip | |
allow sbrk(-x) to de-allocate user memory
| -rw-r--r-- | defs.h | 1 | ||||
| -rw-r--r-- | proc.c | 9 | ||||
| -rw-r--r-- | usertests.c | 57 | ||||
| -rw-r--r-- | vm.c | 26 | 
4 files changed, 89 insertions, 4 deletions
| @@ -159,6 +159,7 @@ void            vminit(void);  pde_t*          setupkvm(void);  char*           uva2ka(pde_t*, char*);  int             allocuvm(pde_t*, char*, uint); +int             deallocuvm(pde_t *pgdir, char *addr, uint sz);  void            freevm(pde_t*);  void            inituvm(pde_t*, char*, char*, uint);  int             loaduvm(pde_t*, char*, struct inode *ip, uint, uint); @@ -142,8 +142,13 @@ userinit(void)  int  growproc(int n)  { -  if (!allocuvm(proc->pgdir, (char *)proc->sz, n)) -    return -1; +  if(n > 0){ +    if (!allocuvm(proc->pgdir, (char *)proc->sz, n)) +      return -1; +  } else if(n < 0){ +    if (!deallocuvm(proc->pgdir, (char *)(proc->sz + n), 0 - n)) +      return -1; +  }    proc->sz += n;    switchuvm(proc);    return 0; diff --git a/usertests.c b/usertests.c index 247cc95..9ad6448 100644 --- a/usertests.c +++ b/usertests.c @@ -1232,7 +1232,11 @@ forktest(void)  void  sbrktest(void)  { +  int pid; +    printf(stdout, "sbrk test\n"); + +  // can one sbrk() less than a page?    char *a = sbrk(0);    int i;    for(i = 0; i < 5000; i++){ @@ -1244,7 +1248,7 @@ sbrktest(void)      *b = 1;      a = b + 1;    } -  int pid = fork(); +  pid = fork();    if(pid < 0){      printf(stdout, "sbrk test fork failed\n");      exit(); @@ -1258,6 +1262,57 @@ sbrktest(void)    if(pid == 0)      exit();    wait(); + +  // can one allocate the full 640K? +  a = sbrk(0); +  uint amt = (640 * 1024) - (uint) a; +  char *p = sbrk(amt); +  if(p != a){ +    printf(stdout, "sbrk test failed 640K test, p %x a %x\n", p, a); +    exit(); +  } +  char *lastaddr = (char *)(640 * 1024 - 1); +  *lastaddr = 99; + +  // is one forbidden from allocating more than 640K? +  c = sbrk(4096); +  if(c != (char *) 0xffffffff){ +    printf(stdout, "sbrk allocated more than 640K, c %x\n", c); +    exit(); +  } + +  // can one de-allocate? +  a = sbrk(0); +  c = sbrk(-4096); +  if(c == (char *) 0xffffffff){ +    printf(stdout, "sbrk could not deallocate\n"); +    exit(); +  } +  c = sbrk(0); +  if(c != a - 4096){ +    printf(stdout, "sbrk deallocation produced wrong address, a %x c %x\n", a, c); +    exit(); +  } + +  // can one re-allocate that page? +  a = sbrk(0); +  c = sbrk(4096); +  if(c != a || sbrk(0) != a + 4096){ +    printf(stdout, "sbrk re-allocation failed, a %x c %x\n", a, c); +    exit(); +  } +  if(*lastaddr == 99){ +    // should be zero +    printf(stdout, "sbrk de-allocation didn't really deallocate\n"); +    exit(); +  } + +  c = sbrk(4096); +  if(c != (char *) 0xffffffff){ +    printf(stdout, "sbrk was able to re-allocate beyond 640K, c %x\n", c); +    exit(); +  } +    printf(stdout, "sbrk test OK\n");  } @@ -198,7 +198,7 @@ uva2ka(pde_t *pgdir, char *uva)  int  allocuvm(pde_t *pgdir, char *addr, uint sz)  { -  if (addr + sz >= (char*)USERTOP) +  if (addr + sz > (char*)USERTOP)      return 0;    char *first = PGROUNDDOWN(addr);    char *last = PGROUNDDOWN(addr + sz - 1); @@ -218,6 +218,30 @@ allocuvm(pde_t *pgdir, char *addr, uint sz)    return 1;  } +// deallocate some of the user pages, in response to sbrk() +// with a negative argument. if addr is not page-aligned, +// then only deallocates starting at the next page boundary. +int +deallocuvm(pde_t *pgdir, char *addr, uint sz) +{ +  if (addr + sz > (char*)USERTOP) +    return 0; +  char *first = (char*) PGROUNDUP((uint)addr); +  char *last = PGROUNDDOWN(addr + sz - 1); +  char *a; +  for(a = first; a <= last; a += PGSIZE){ +    pte_t *pte = walkpgdir(pgdir, a, 0); +    if(pte && (*pte & PTE_P) != 0){ +      uint pa = PTE_ADDR(*pte); +      if(pa == 0) +        panic("deallocuvm"); +      kfree((void *) pa, PGSIZE); +      *pte = 0; +    } +  } +  return 1; +} +  // free a page table and all the physical memory pages  // in the user part.  void | 
