allow sbrk(-x) to de-allocate user memory
This commit is contained in:
parent
c4cc10da7e
commit
83d2db91f7
4 changed files with 89 additions and 4 deletions
1
defs.h
1
defs.h
|
@ -159,6 +159,7 @@ void vminit(void);
|
||||||
pde_t* setupkvm(void);
|
pde_t* setupkvm(void);
|
||||||
char* uva2ka(pde_t*, char*);
|
char* uva2ka(pde_t*, char*);
|
||||||
int allocuvm(pde_t*, char*, uint);
|
int allocuvm(pde_t*, char*, uint);
|
||||||
|
int deallocuvm(pde_t *pgdir, char *addr, uint sz);
|
||||||
void freevm(pde_t*);
|
void freevm(pde_t*);
|
||||||
void inituvm(pde_t*, char*, char*, uint);
|
void inituvm(pde_t*, char*, char*, uint);
|
||||||
int loaduvm(pde_t*, char*, struct inode *ip, uint, uint);
|
int loaduvm(pde_t*, char*, struct inode *ip, uint, uint);
|
||||||
|
|
9
proc.c
9
proc.c
|
@ -142,8 +142,13 @@ userinit(void)
|
||||||
int
|
int
|
||||||
growproc(int n)
|
growproc(int n)
|
||||||
{
|
{
|
||||||
if (!allocuvm(proc->pgdir, (char *)proc->sz, n))
|
if(n > 0){
|
||||||
return -1;
|
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;
|
proc->sz += n;
|
||||||
switchuvm(proc);
|
switchuvm(proc);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
57
usertests.c
57
usertests.c
|
@ -1232,7 +1232,11 @@ forktest(void)
|
||||||
void
|
void
|
||||||
sbrktest(void)
|
sbrktest(void)
|
||||||
{
|
{
|
||||||
|
int pid;
|
||||||
|
|
||||||
printf(stdout, "sbrk test\n");
|
printf(stdout, "sbrk test\n");
|
||||||
|
|
||||||
|
// can one sbrk() less than a page?
|
||||||
char *a = sbrk(0);
|
char *a = sbrk(0);
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < 5000; i++){
|
for(i = 0; i < 5000; i++){
|
||||||
|
@ -1244,7 +1248,7 @@ sbrktest(void)
|
||||||
*b = 1;
|
*b = 1;
|
||||||
a = b + 1;
|
a = b + 1;
|
||||||
}
|
}
|
||||||
int pid = fork();
|
pid = fork();
|
||||||
if(pid < 0){
|
if(pid < 0){
|
||||||
printf(stdout, "sbrk test fork failed\n");
|
printf(stdout, "sbrk test fork failed\n");
|
||||||
exit();
|
exit();
|
||||||
|
@ -1258,6 +1262,57 @@ sbrktest(void)
|
||||||
if(pid == 0)
|
if(pid == 0)
|
||||||
exit();
|
exit();
|
||||||
wait();
|
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");
|
printf(stdout, "sbrk test OK\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
26
vm.c
26
vm.c
|
@ -198,7 +198,7 @@ uva2ka(pde_t *pgdir, char *uva)
|
||||||
int
|
int
|
||||||
allocuvm(pde_t *pgdir, char *addr, uint sz)
|
allocuvm(pde_t *pgdir, char *addr, uint sz)
|
||||||
{
|
{
|
||||||
if (addr + sz >= (char*)USERTOP)
|
if (addr + sz > (char*)USERTOP)
|
||||||
return 0;
|
return 0;
|
||||||
char *first = PGROUNDDOWN(addr);
|
char *first = PGROUNDDOWN(addr);
|
||||||
char *last = PGROUNDDOWN(addr + sz - 1);
|
char *last = PGROUNDDOWN(addr + sz - 1);
|
||||||
|
@ -218,6 +218,30 @@ allocuvm(pde_t *pgdir, char *addr, uint sz)
|
||||||
return 1;
|
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
|
// free a page table and all the physical memory pages
|
||||||
// in the user part.
|
// in the user part.
|
||||||
void
|
void
|
||||||
|
|
Loading…
Reference in a new issue