summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--kernel/defs.h4
-rw-r--r--kernel/kernelvec.S2
-rw-r--r--kernel/proc.c44
-rw-r--r--kernel/syscall.c46
-rw-r--r--kernel/sysfile.c26
-rw-r--r--kernel/sysproc.c16
-rw-r--r--kernel/trap.c27
-rw-r--r--kernel/vm.c32
-rwxr-xr-xrunoff5
-rw-r--r--runoff.list98
-rw-r--r--user/cow.c196
-rw-r--r--user/usertests.c13
13 files changed, 376 insertions, 134 deletions
diff --git a/Makefile b/Makefile
index 88130e1..03befd7 100644
--- a/Makefile
+++ b/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)
diff --git a/kernel/defs.h b/kernel/defs.h
index 1b397fe..bd89af0 100644
--- a/kernel/defs.h
+++ b/kernel/defs.h
@@ -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);
diff --git a/kernel/kernelvec.S b/kernel/kernelvec.S
index 4f52688..e9b0ced 100644
--- a/kernel/kernelvec.S
+++ b/kernel/kernelvec.S
@@ -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)
diff --git a/kernel/proc.c b/kernel/proc.c
index c12d97e..8ea09b5 100644
--- a/kernel/proc.c
+++ b/kernel/proc.c
@@ -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,7 +171,8 @@ proc_freepagetable(pagetable_t pagetable, uint64 sz)
{
unmappages(pagetable, TRAMPOLINE, PGSIZE, 0);
unmappages(pagetable, TRAMPOLINE-PGSIZE, PGSIZE, 0);
- uvmfree(pagetable, sz);
+ if(sz > 0)
+ uvmfree(pagetable, sz);
}
// a user program that calls exec("/init")
@@ -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;
diff --git a/kernel/syscall.c b/kernel/syscall.c
index 8e9d51c..a054da2 100644
--- a/kernel/syscall.c
+++ b/kernel/syscall.c
@@ -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);
-
-static int (*syscalls[])(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 uint64 (*syscalls[])(void) = {
[SYS_fork] sys_fork,
[SYS_exit] sys_exit,
[SYS_wait] sys_wait,
diff --git a/kernel/sysfile.c b/kernel/sysfile.c
index 33f37f2..533e097 100644
--- a/kernel/sysfile.c
+++ b/kernel/sysfile.c
@@ -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
diff --git a/kernel/sysproc.c b/kernel/sysproc.c
index 65dde26..face81a 100644
--- a/kernel/sysproc.c
+++ b/kernel/sysproc.c
@@ -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;
diff --git a/kernel/trap.c b/kernel/trap.c
index 6c0d04b..018b7db 100644
--- a/kernel/trap.c
+++ b/kernel/trap.c
@@ -37,7 +37,7 @@ void
usertrap(void)
{
int which_dev = 0;
-
+
if((r_sstatus() & SSTATUS_SPP) != 0)
panic("usertrap: not from user mode");
@@ -49,8 +49,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,
diff --git a/kernel/vm.c b/kernel/vm.c
index 580669f..bdb53c2 100644
--- a/kernel/vm.c
+++ b/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,10 +297,18 @@ 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.
diff --git a/runoff b/runoff
index be362d0..c6580ca 100755
--- a/runoff
+++ b/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}'`
diff --git a/runoff.list b/runoff.list
index 9fdc9e0..6e6af18 100644
--- a/runoff.list
+++ b/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
diff --git a/user/cow.c b/user/cow.c
new file mode 100644
index 0000000..45efc98
--- /dev/null
+++ b/user/cow.c
@@ -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();
+}
diff --git a/user/usertests.c b/user/usertests.c
index beca8f9..ef70bfb 100644
--- a/user/usertests.c
+++ b/user/usertests.c
@@ -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();
}