Merge branch 'riscv' into riscv-proc
This commit is contained in:
commit
1e4d7065d6
1
Makefile
1
Makefile
|
@ -128,6 +128,7 @@ UPROGS=\
|
|||
$U/_usertests\
|
||||
$U/_wc\
|
||||
$U/_zombie\
|
||||
$U/_cow\
|
||||
|
||||
fs.img: mkfs/mkfs README $(UPROGS)
|
||||
mkfs/mkfs fs.img README $(UPROGS)
|
||||
|
|
|
@ -185,9 +185,9 @@ pagetable_t uvmcreate(void);
|
|||
void uvminit(pagetable_t, uchar *, uint);
|
||||
uint64 uvmalloc(pagetable_t, uint64, uint64);
|
||||
uint64 uvmdealloc(pagetable_t, uint64, uint64);
|
||||
void uvmcopy(pagetable_t, pagetable_t, uint64);
|
||||
int uvmcopy(pagetable_t, pagetable_t, uint64);
|
||||
void uvmfree(pagetable_t, uint64);
|
||||
void mappages(pagetable_t, uint64, uint64, uint64, int);
|
||||
int mappages(pagetable_t, uint64, uint64, uint64, int);
|
||||
void unmappages(pagetable_t, uint64, uint64, int);
|
||||
uint64 walkaddr(pagetable_t, uint64);
|
||||
int copyout(pagetable_t, uint64, char *, uint64);
|
||||
|
|
|
@ -47,7 +47,7 @@ kernelvec:
|
|||
ld ra, 0(sp)
|
||||
ld sp, 8(sp)
|
||||
ld gp, 16(sp)
|
||||
ld tp, 24(sp)
|
||||
// not this, in case we moved CPUs: ld tp, 24(sp)
|
||||
ld t0, 32(sp)
|
||||
ld t1, 40(sp)
|
||||
ld t2, 48(sp)
|
||||
|
|
|
@ -111,6 +111,30 @@ found:
|
|||
return p;
|
||||
}
|
||||
|
||||
// free a proc structure and the data hanging from it,
|
||||
// including user pages.
|
||||
// the proc lock must be held.
|
||||
static void
|
||||
freeproc(struct proc *p)
|
||||
{
|
||||
if(p->kstack)
|
||||
kfree(p->kstack);
|
||||
p->kstack = 0;
|
||||
if(p->tf)
|
||||
kfree((void*)p->tf);
|
||||
p->tf = 0;
|
||||
if(p->pagetable)
|
||||
proc_freepagetable(p->pagetable, p->sz);
|
||||
p->pagetable = 0;
|
||||
p->sz = 0;
|
||||
p->pid = 0;
|
||||
p->parent = 0;
|
||||
p->name[0] = 0;
|
||||
p->chan = 0;
|
||||
p->killed = 0;
|
||||
p->state = UNUSED;
|
||||
}
|
||||
|
||||
// Create a page table for a given process,
|
||||
// with no users pages, but with trampoline pages.
|
||||
// Called both when creating a process, and
|
||||
|
@ -147,6 +171,7 @@ proc_freepagetable(pagetable_t pagetable, uint64 sz)
|
|||
{
|
||||
unmappages(pagetable, TRAMPOLINE, PGSIZE, 0);
|
||||
unmappages(pagetable, TRAMPOLINE-PGSIZE, PGSIZE, 0);
|
||||
if(sz > 0)
|
||||
uvmfree(pagetable, sz);
|
||||
}
|
||||
|
||||
|
@ -226,7 +251,10 @@ fork(void)
|
|||
}
|
||||
|
||||
// Copy user memory from parent to child.
|
||||
uvmcopy(p->pagetable, np->pagetable, p->sz);
|
||||
if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){
|
||||
freeproc(np);
|
||||
return -1;
|
||||
}
|
||||
np->sz = p->sz;
|
||||
|
||||
np->parent = p;
|
||||
|
@ -342,17 +370,7 @@ wait(void)
|
|||
if(np->state == ZOMBIE){
|
||||
// Found one.
|
||||
pid = np->pid;
|
||||
kfree(np->kstack);
|
||||
np->kstack = 0;
|
||||
kfree((void*)np->tf);
|
||||
np->tf = 0;
|
||||
proc_freepagetable(np->pagetable, np->sz);
|
||||
np->pagetable = 0;
|
||||
np->pid = 0;
|
||||
np->parent = 0;
|
||||
np->name[0] = 0;
|
||||
np->killed = 0;
|
||||
np->state = UNUSED;
|
||||
freeproc(np);
|
||||
release(&np->lock);
|
||||
release(&p->lock);
|
||||
return pid;
|
||||
|
|
|
@ -117,29 +117,29 @@ argstr(int n, char *buf, int max)
|
|||
return fetchstr(addr, buf, max);
|
||||
}
|
||||
|
||||
extern int sys_chdir(void);
|
||||
extern int sys_close(void);
|
||||
extern int sys_dup(void);
|
||||
extern int sys_exec(void);
|
||||
extern int sys_exit(void);
|
||||
extern int sys_fork(void);
|
||||
extern int sys_fstat(void);
|
||||
extern int sys_getpid(void);
|
||||
extern int sys_kill(void);
|
||||
extern int sys_link(void);
|
||||
extern int sys_mkdir(void);
|
||||
extern int sys_mknod(void);
|
||||
extern int sys_open(void);
|
||||
extern int sys_pipe(void);
|
||||
extern int sys_read(void);
|
||||
extern int sys_sbrk(void);
|
||||
extern int sys_sleep(void);
|
||||
extern int sys_unlink(void);
|
||||
extern int sys_wait(void);
|
||||
extern int sys_write(void);
|
||||
extern int sys_uptime(void);
|
||||
extern uint64 sys_chdir(void);
|
||||
extern uint64 sys_close(void);
|
||||
extern uint64 sys_dup(void);
|
||||
extern uint64 sys_exec(void);
|
||||
extern uint64 sys_exit(void);
|
||||
extern uint64 sys_fork(void);
|
||||
extern uint64 sys_fstat(void);
|
||||
extern uint64 sys_getpid(void);
|
||||
extern uint64 sys_kill(void);
|
||||
extern uint64 sys_link(void);
|
||||
extern uint64 sys_mkdir(void);
|
||||
extern uint64 sys_mknod(void);
|
||||
extern uint64 sys_open(void);
|
||||
extern uint64 sys_pipe(void);
|
||||
extern uint64 sys_read(void);
|
||||
extern uint64 sys_sbrk(void);
|
||||
extern uint64 sys_sleep(void);
|
||||
extern uint64 sys_unlink(void);
|
||||
extern uint64 sys_wait(void);
|
||||
extern uint64 sys_write(void);
|
||||
extern uint64 sys_uptime(void);
|
||||
|
||||
static int (*syscalls[])(void) = {
|
||||
static uint64 (*syscalls[])(void) = {
|
||||
[SYS_fork] sys_fork,
|
||||
[SYS_exit] sys_exit,
|
||||
[SYS_wait] sys_wait,
|
||||
|
|
|
@ -52,7 +52,7 @@ fdalloc(struct file *f)
|
|||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_dup(void)
|
||||
{
|
||||
struct file *f;
|
||||
|
@ -66,7 +66,7 @@ sys_dup(void)
|
|||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_read(void)
|
||||
{
|
||||
struct file *f;
|
||||
|
@ -78,7 +78,7 @@ sys_read(void)
|
|||
return fileread(f, p, n);
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_write(void)
|
||||
{
|
||||
struct file *f;
|
||||
|
@ -91,7 +91,7 @@ sys_write(void)
|
|||
return filewrite(f, p, n);
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_close(void)
|
||||
{
|
||||
int fd;
|
||||
|
@ -104,7 +104,7 @@ sys_close(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_fstat(void)
|
||||
{
|
||||
struct file *f;
|
||||
|
@ -116,7 +116,7 @@ sys_fstat(void)
|
|||
}
|
||||
|
||||
// Create the path new as a link to the same inode as old.
|
||||
int
|
||||
uint64
|
||||
sys_link(void)
|
||||
{
|
||||
char name[DIRSIZ], new[MAXPATH], old[MAXPATH];
|
||||
|
@ -182,7 +182,7 @@ isdirempty(struct inode *dp)
|
|||
}
|
||||
|
||||
//PAGEBREAK!
|
||||
int
|
||||
uint64
|
||||
sys_unlink(void)
|
||||
{
|
||||
struct inode *ip, *dp;
|
||||
|
@ -284,7 +284,7 @@ create(char *path, short type, short major, short minor)
|
|||
return ip;
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_open(void)
|
||||
{
|
||||
char path[MAXPATH];
|
||||
|
@ -347,7 +347,7 @@ sys_open(void)
|
|||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_mkdir(void)
|
||||
{
|
||||
char path[MAXPATH];
|
||||
|
@ -363,7 +363,7 @@ sys_mkdir(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_mknod(void)
|
||||
{
|
||||
struct inode *ip;
|
||||
|
@ -383,7 +383,7 @@ sys_mknod(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_chdir(void)
|
||||
{
|
||||
char path[MAXPATH];
|
||||
|
@ -408,7 +408,7 @@ sys_chdir(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_exec(void)
|
||||
{
|
||||
char path[MAXPATH], *argv[MAXARG];
|
||||
|
@ -446,7 +446,7 @@ sys_exec(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_pipe(void)
|
||||
{
|
||||
uint64 fdarray; // user pointer to array of two integers
|
||||
|
|
|
@ -7,32 +7,32 @@
|
|||
#include "spinlock.h"
|
||||
#include "proc.h"
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_exit(void)
|
||||
{
|
||||
exit();
|
||||
return 0; // not reached
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_getpid(void)
|
||||
{
|
||||
return myproc()->pid;
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_fork(void)
|
||||
{
|
||||
return fork();
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_wait(void)
|
||||
{
|
||||
return wait();
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_sbrk(void)
|
||||
{
|
||||
int addr;
|
||||
|
@ -46,7 +46,7 @@ sys_sbrk(void)
|
|||
return addr;
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_sleep(void)
|
||||
{
|
||||
int n;
|
||||
|
@ -67,7 +67,7 @@ sys_sleep(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
uint64
|
||||
sys_kill(void)
|
||||
{
|
||||
int pid;
|
||||
|
@ -79,7 +79,7 @@ sys_kill(void)
|
|||
|
||||
// return how many clock tick interrupts have occurred
|
||||
// since start.
|
||||
int
|
||||
uint64
|
||||
sys_uptime(void)
|
||||
{
|
||||
uint xticks;
|
||||
|
|
|
@ -50,8 +50,6 @@ usertrap(void)
|
|||
// save user program counter.
|
||||
p->tf->epc = r_sepc();
|
||||
|
||||
intr_on();
|
||||
|
||||
if(r_scause() == 8){
|
||||
// system call
|
||||
|
||||
|
@ -59,11 +57,15 @@ usertrap(void)
|
|||
// but we want to return to the next instruction.
|
||||
p->tf->epc += 4;
|
||||
|
||||
// an interrupt will change sstatus &c registers,
|
||||
// so don't enable until done with those registers.
|
||||
intr_on();
|
||||
|
||||
syscall();
|
||||
} else if((which_dev = devintr()) != 0){
|
||||
// ok
|
||||
} else {
|
||||
printf("usertrap(): unexpected scause 0x%p pid=%d\n", r_scause(), p->pid);
|
||||
printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
|
||||
printf(" sepc=%p stval=%p\n", r_sepc(), r_stval());
|
||||
p->killed = 1;
|
||||
}
|
||||
|
@ -121,12 +123,14 @@ usertrapret(void)
|
|||
((void (*)(uint64,uint64))TRAMPOLINE)(TRAMPOLINE - PGSIZE, satp);
|
||||
}
|
||||
|
||||
// interrupts and exceptions from kernel code go here,
|
||||
// interrupts and exceptions from kernel code go here via kernelvec,
|
||||
// on whatever the current kernel stack is.
|
||||
// must be 4-byte aligned to fit in stvec.
|
||||
void
|
||||
kerneltrap()
|
||||
{
|
||||
int which_dev = 0;
|
||||
uint64 sepc = r_sepc();
|
||||
uint64 sstatus = r_sstatus();
|
||||
uint64 scause = r_scause();
|
||||
|
||||
|
@ -135,11 +139,20 @@ kerneltrap()
|
|||
if(intr_get() != 0)
|
||||
panic("kerneltrap: interrupts enabled");
|
||||
|
||||
if(devintr() == 0){
|
||||
printf("scause 0x%p\n", scause);
|
||||
if((which_dev = devintr()) == 0){
|
||||
printf("scause %p\n", scause);
|
||||
printf("sepc=%p stval=%p\n", r_sepc(), r_stval());
|
||||
panic("kerneltrap");
|
||||
}
|
||||
|
||||
// give up the CPU if this is a timer interrupt.
|
||||
if(which_dev == 2 && myproc() != 0 && myproc()->state == RUNNING)
|
||||
yield();
|
||||
|
||||
// the yield() may have caused some traps to occur,
|
||||
// so restore trap registers for use by kernelvec.S's sepc instruction.
|
||||
w_sepc(sepc);
|
||||
w_sstatus(sstatus);
|
||||
}
|
||||
|
||||
// check if it's an external interrupt or software interrupt,
|
||||
|
|
32
kernel/vm.c
32
kernel/vm.c
|
@ -97,8 +97,8 @@ walk(pagetable_t pagetable, uint64 va, int alloc)
|
|||
}
|
||||
|
||||
// Look up a virtual address, return the physical address,
|
||||
// Can only be used to look up user pages.
|
||||
// or 0 if not mapped.
|
||||
// Can only be used to look up user pages.
|
||||
uint64
|
||||
walkaddr(pagetable_t pagetable, uint64 va)
|
||||
{
|
||||
|
@ -119,8 +119,9 @@ walkaddr(pagetable_t pagetable, uint64 va)
|
|||
|
||||
// Create PTEs for virtual addresses starting at va that refer to
|
||||
// physical addresses starting at pa. va and size might not
|
||||
// be page-aligned.
|
||||
void
|
||||
// be page-aligned. Returns 0 on success, -1 if walk() couldn't
|
||||
// allocate a needed page-table page.
|
||||
int
|
||||
mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
|
||||
{
|
||||
uint64 a, last;
|
||||
|
@ -130,7 +131,7 @@ mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
|
|||
last = PGROUNDDOWN(va + size - 1);
|
||||
for(;;){
|
||||
if((pte = walk(pagetable, a, 1)) == 0)
|
||||
panic("mappages: walk");
|
||||
return -1;
|
||||
if(*pte & PTE_V)
|
||||
panic("remap");
|
||||
*pte = PA2PTE(pa) | perm | PTE_V;
|
||||
|
@ -139,6 +140,7 @@ mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
|
|||
a += PGSIZE;
|
||||
pa += PGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Remove mappings from a page table. The mappings in
|
||||
|
@ -222,7 +224,11 @@ uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz)
|
|||
return 0;
|
||||
}
|
||||
memset(mem, 0, PGSIZE);
|
||||
mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U);
|
||||
if(mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U) != 0){
|
||||
kfree(mem);
|
||||
uvmdealloc(pagetable, a, oldsz);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return newsz;
|
||||
}
|
||||
|
@ -273,7 +279,9 @@ uvmfree(pagetable_t pagetable, uint64 sz)
|
|||
// its memory into a child's page table.
|
||||
// Copies both the page table and the
|
||||
// physical memory.
|
||||
void
|
||||
// returns 0 on success, -1 on failure.
|
||||
// frees any allocated pages on failure.
|
||||
int
|
||||
uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
|
||||
{
|
||||
pte_t *pte;
|
||||
|
@ -289,11 +297,19 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
|
|||
pa = PTE2PA(*pte);
|
||||
flags = PTE_FLAGS(*pte);
|
||||
if((mem = kalloc()) == 0)
|
||||
panic("uvmcopy: kalloc failed");
|
||||
goto err;
|
||||
memmove(mem, (char*)pa, PGSIZE);
|
||||
mappages(new, i, PGSIZE, (uint64)mem, flags);
|
||||
if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){
|
||||
kfree(mem);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
err:
|
||||
unmappages(new, 0, i, 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Copy from kernel to user.
|
||||
// Copy len bytes from src to virtual address dstva in a given page table.
|
||||
|
|
5
runoff
5
runoff
|
@ -12,7 +12,10 @@ pad()
|
|||
|
||||
# create formatted (numbered) files
|
||||
mkdir -p fmt
|
||||
rm -f fmt/*
|
||||
mkdir -p fmt/kernel
|
||||
mkdir -p fmt/user
|
||||
rm -f fmt/kernel/*
|
||||
rm -f fmt/user/*
|
||||
cp README fmt
|
||||
echo > fmt/blank
|
||||
files=`grep -v '^#' runoff.list | awk '{print $1}'`
|
||||
|
|
98
runoff.list
98
runoff.list
|
@ -1,76 +1,64 @@
|
|||
# basic headers
|
||||
types.h
|
||||
param.h
|
||||
memlayout.h
|
||||
defs.h
|
||||
x86.h
|
||||
asm.h
|
||||
mmu.h
|
||||
elf.h
|
||||
date.h
|
||||
kernel/types.h
|
||||
kernel/param.h
|
||||
kernel/memlayout.h
|
||||
kernel/defs.h
|
||||
kernel/riscv.h
|
||||
kernel/elf.h
|
||||
kernel/date.h
|
||||
|
||||
# entering xv6
|
||||
entry.S
|
||||
entryother.S
|
||||
main.c
|
||||
kernel/entry.S
|
||||
kernel/main.c
|
||||
|
||||
# locks
|
||||
spinlock.h
|
||||
spinlock.c
|
||||
kernel/spinlock.h
|
||||
kernel/spinlock.c
|
||||
|
||||
# processes
|
||||
vm.c
|
||||
proc.h
|
||||
proc.c
|
||||
swtch.S
|
||||
kalloc.c
|
||||
kernel/vm.c
|
||||
kernel/proc.h
|
||||
kernel/proc.c
|
||||
kernel/swtch.S
|
||||
kernel/kalloc.c
|
||||
|
||||
# system calls
|
||||
traps.h
|
||||
vectors.pl
|
||||
trapasm.S
|
||||
trap.c
|
||||
syscall.h
|
||||
syscall.c
|
||||
sysproc.c
|
||||
user/usys.pl
|
||||
kernel/trap.c
|
||||
kernel/syscall.h
|
||||
kernel/syscall.c
|
||||
kernel/sysproc.c
|
||||
|
||||
# file system
|
||||
buf.h
|
||||
sleeplock.h
|
||||
fcntl.h
|
||||
stat.h
|
||||
fs.h
|
||||
file.h
|
||||
ide.c
|
||||
bio.c
|
||||
sleeplock.c
|
||||
log.c
|
||||
fs.c
|
||||
file.c
|
||||
sysfile.c
|
||||
exec.c
|
||||
kernel/buf.h
|
||||
kernel/sleeplock.h
|
||||
kernel/fcntl.h
|
||||
kernel/stat.h
|
||||
kernel/fs.h
|
||||
kernel/file.h
|
||||
kernel/virtio_disk.c
|
||||
kernel/bio.c
|
||||
kernel/sleeplock.c
|
||||
kernel/log.c
|
||||
kernel/fs.c
|
||||
kernel/file.c
|
||||
kernel/sysfile.c
|
||||
kernel/exec.c
|
||||
|
||||
# pipes
|
||||
pipe.c
|
||||
kernel/pipe.c
|
||||
|
||||
# string operations
|
||||
string.c
|
||||
kernel/string.c
|
||||
|
||||
# low-level hardware
|
||||
mp.h
|
||||
mp.c
|
||||
lapic.c
|
||||
ioapic.c
|
||||
kbd.h
|
||||
kbd.c
|
||||
console.c
|
||||
uart.c
|
||||
kernel/uart.c
|
||||
|
||||
# user-level
|
||||
initcode.S
|
||||
usys.S
|
||||
init.c
|
||||
sh.c
|
||||
user/initcode.S
|
||||
user/usys.S
|
||||
user/init.c
|
||||
user/sh.c
|
||||
|
||||
# link
|
||||
kernel.ld
|
||||
kernel/kernel.ld
|
||||
|
|
196
user/cow.c
Normal file
196
user/cow.c
Normal file
|
@ -0,0 +1,196 @@
|
|||
//
|
||||
// tests for copy-on-write fork() assignment.
|
||||
//
|
||||
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/memlayout.h"
|
||||
#include "user/user.h"
|
||||
|
||||
// allocate more than half of physical memory,
|
||||
// then fork. this will fail in the default
|
||||
// kernel, which does not support copy-on-write.
|
||||
void
|
||||
simpletest()
|
||||
{
|
||||
uint64 phys_size = PHYSTOP - KERNBASE;
|
||||
int sz = (phys_size / 3) * 2;
|
||||
|
||||
printf(1, "simple: ");
|
||||
|
||||
char *p = sbrk(sz);
|
||||
if(p == (char*)0xffffffffffffffffL){
|
||||
printf(1, "sbrk(%d) failed\n", sz);
|
||||
exit();
|
||||
}
|
||||
|
||||
for(char *q = p; q < p + sz; q += 4096){
|
||||
*(int*)q = getpid();
|
||||
}
|
||||
|
||||
int pid = fork();
|
||||
if(pid < 0){
|
||||
printf(1, "fork() failed\n");
|
||||
exit();
|
||||
}
|
||||
|
||||
if(pid == 0)
|
||||
exit();
|
||||
|
||||
wait();
|
||||
|
||||
if(sbrk(-sz) == (char*)0xffffffffffffffffL){
|
||||
printf(1, "sbrk(-%d) failed\n", sz);
|
||||
exit();
|
||||
}
|
||||
|
||||
printf(1, "ok\n");
|
||||
}
|
||||
|
||||
// three processes all write COW memory.
|
||||
// this causes more than half of physical memory
|
||||
// to be allocated, so it also checks whether
|
||||
// copied pages are freed.
|
||||
void
|
||||
threetest()
|
||||
{
|
||||
uint64 phys_size = PHYSTOP - KERNBASE;
|
||||
int sz = phys_size / 4;
|
||||
int pid1, pid2;
|
||||
|
||||
printf(1, "three: ");
|
||||
|
||||
char *p = sbrk(sz);
|
||||
if(p == (char*)0xffffffffffffffffL){
|
||||
printf(1, "sbrk(%d) failed\n", sz);
|
||||
exit();
|
||||
}
|
||||
|
||||
pid1 = fork();
|
||||
if(pid1 < 0){
|
||||
printf(1, "fork failed\n");
|
||||
exit();
|
||||
}
|
||||
if(pid1 == 0){
|
||||
pid2 = fork();
|
||||
if(pid2 < 0){
|
||||
printf(1, "fork failed");
|
||||
exit();
|
||||
}
|
||||
if(pid2 == 0){
|
||||
for(char *q = p; q < p + (sz/5)*4; q += 4096){
|
||||
*(int*)q = getpid();
|
||||
}
|
||||
for(char *q = p; q < p + (sz/5)*4; q += 4096){
|
||||
if(*(int*)q != getpid()){
|
||||
printf(1, "wrong content\n");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
exit();
|
||||
}
|
||||
for(char *q = p; q < p + (sz/2); q += 4096){
|
||||
*(int*)q = 9999;
|
||||
}
|
||||
exit();
|
||||
}
|
||||
|
||||
for(char *q = p; q < p + sz; q += 4096){
|
||||
*(int*)q = getpid();
|
||||
}
|
||||
|
||||
wait();
|
||||
|
||||
sleep(1);
|
||||
|
||||
for(char *q = p; q < p + sz; q += 4096){
|
||||
if(*(int*)q != getpid()){
|
||||
printf(1, "wrong content\n");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
if(sbrk(-sz) == (char*)0xffffffffffffffffL){
|
||||
printf(1, "sbrk(-%d) failed\n", sz);
|
||||
exit();
|
||||
}
|
||||
|
||||
printf(1, "ok\n");
|
||||
}
|
||||
|
||||
char junk1[4096];
|
||||
int fds[2];
|
||||
char junk2[4096];
|
||||
char buf[4096];
|
||||
char junk3[4096];
|
||||
|
||||
// test whether copyout() simulates COW faults.
|
||||
void
|
||||
filetest()
|
||||
{
|
||||
int parent = getpid();
|
||||
|
||||
printf(1, "file test: ");
|
||||
|
||||
buf[0] = 99;
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
if(pipe(fds) != 0){
|
||||
printf(1, "pipe() failed\n");
|
||||
exit();
|
||||
}
|
||||
int pid = fork();
|
||||
if(pid < 0){
|
||||
printf(1, "fork failed\n");
|
||||
exit();
|
||||
}
|
||||
if(pid == 0){
|
||||
sleep(1);
|
||||
if(read(fds[0], buf, sizeof(i)) != sizeof(i)){
|
||||
printf(1, "read failed\n");
|
||||
kill(parent);
|
||||
exit();
|
||||
}
|
||||
sleep(1);
|
||||
int j = *(int*)buf;
|
||||
if(j != i){
|
||||
printf(1, "read the wrong value\n");
|
||||
kill(parent);
|
||||
exit();
|
||||
}
|
||||
exit();
|
||||
}
|
||||
if(write(fds[1], &i, sizeof(i)) != sizeof(i)){
|
||||
printf(1, "write failed\n");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
wait();
|
||||
|
||||
if(buf[0] != 99){
|
||||
printf(1, "child overwrote parent\n");
|
||||
exit();
|
||||
}
|
||||
|
||||
printf(1, "ok\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
simpletest();
|
||||
|
||||
// check that the first simpletest() freed the physical memory.
|
||||
simpletest();
|
||||
|
||||
threetest();
|
||||
threetest();
|
||||
threetest();
|
||||
|
||||
filetest();
|
||||
|
||||
printf(1, "ALL COW TESTS PASSED\n");
|
||||
|
||||
exit();
|
||||
}
|
|
@ -1438,6 +1438,13 @@ sbrktest(void)
|
|||
printf(stdout, "sbrk test\n");
|
||||
oldbrk = sbrk(0);
|
||||
|
||||
// does sbrk() return the expected failure value?
|
||||
a = sbrk(1024*1024*1024);
|
||||
if(a != (char*)0xffffffffffffffffL){
|
||||
printf(stdout, "sbrk(<toomuch>) returned %p\n", a);
|
||||
exit();
|
||||
}
|
||||
|
||||
// can one sbrk() less than a page?
|
||||
a = sbrk(0);
|
||||
for(i = 0; i < 5000; i++){
|
||||
|
@ -1466,7 +1473,7 @@ sbrktest(void)
|
|||
|
||||
// can one grow address space to something big?
|
||||
a = sbrk(0);
|
||||
amt = (BIG) - (uint64)a;
|
||||
amt = BIG - (uint64)a;
|
||||
p = sbrk(amt);
|
||||
if (p != a) {
|
||||
printf(stdout, "sbrk test failed to grow big address space; enough phys mem?\n");
|
||||
|
@ -1478,7 +1485,7 @@ sbrktest(void)
|
|||
// can one de-allocate?
|
||||
a = sbrk(0);
|
||||
c = sbrk(-4096);
|
||||
if(c == (char*)0xffffffff){
|
||||
if(c == (char*)0xffffffffffffffffL){
|
||||
printf(stdout, "sbrk could not deallocate\n");
|
||||
exit();
|
||||
}
|
||||
|
@ -1551,7 +1558,7 @@ sbrktest(void)
|
|||
kill(pids[i]);
|
||||
wait();
|
||||
}
|
||||
if(c == (char*)0xffffffff){
|
||||
if(c == (char*)0xffffffffffffffffL){
|
||||
printf(stdout, "failed sbrk leaked memory\n");
|
||||
exit();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue