Compare commits

..

No commits in common. "f5b93ef12f7159f74f80f94729ee4faabe42c360" and "948cfbdb1ff8af3924fe149960824d601df13163" have entirely different histories.

9 changed files with 281 additions and 370 deletions

36
README
View file

@ -6,7 +6,7 @@ ACKNOWLEDGMENTS
xv6 is inspired by John Lions's Commentary on UNIX 6th Edition (Peer xv6 is inspired by John Lions's Commentary on UNIX 6th Edition (Peer
to Peer Communications; ISBN: 1-57398-013-7; 1st edition (June 14, to Peer Communications; ISBN: 1-57398-013-7; 1st edition (June 14,
2000)). See also https://pdos.csail.mit.edu/6.1810/, which provides 2000)). See also https://pdos.csail.mit.edu/6.828/, which provides
pointers to on-line resources for v6. pointers to on-line resources for v6.
The following people have made contributions: Russ Cox (context switching, The following people have made contributions: Russ Cox (context switching,
@ -14,31 +14,29 @@ locking), Cliff Frey (MP), Xiao Yu (MP), Nickolai Zeldovich, and Austin
Clements. Clements.
We are also grateful for the bug reports and patches contributed by We are also grateful for the bug reports and patches contributed by
Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, carlclone, Ian Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, Ian Chen, Dan
Chen, Dan Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi, Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi, eyalz800, Nelson
eyalz800, Nelson Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel Filardo, flespark,
Filardo, flespark, Peter Froehlich, Yakir Goaron, Shivam Handa, Matt Peter Froehlich, Yakir Goaron, Shivam Handa, Matt Harvey, Bryan Henry,
Harvey, Bryan Henry, jaichenhengjie, Jim Huang, Matúš Jókay, John jaichenhengjie, Jim Huang, Matúš Jókay, Alexander Kapshuk, Anders
Jolly, Alexander Kapshuk, Anders Kaseorg, kehao95, Wolfgang Keller, Kaseorg, kehao95, Wolfgang Keller, Jungwoo Kim, Jonathan Kimmitt,
Jungwoo Kim, Jonathan Kimmitt, Eddie Kohler, Vadim Kolontsov, Austin Eddie Kohler, Vadim Kolontsov, Austin Liew, l0stman, Pavan
Liew, l0stman, Pavan Maddamsetti, Imbar Marinescu, Yandong Mao, Matan Maddamsetti, Imbar Marinescu, Yandong Mao, Matan Shabtay, Hitoshi
Shabtay, Hitoshi Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel Nider,
Nider, Hayato Ohhashi, OptimisticSide, Harry Porter, Greg Price, Jude OptimisticSide, Greg Price, Jude Rich, Ayan Shafqat, Eldar Sehayek,
Rich, segfault, Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya Yongming Shen, Fumiya Shigemitsu, Cam Tenny, tyfkda, Warren Toomey,
Shigemitsu, Cam Tenny, tyfkda, Warren Toomey, Stephen Tu, Rafael Ubal, Stephen Tu, Rafael Ubal, Amane Uehara, Pablo Ventura, Xi Wang, Keiichi
Amane Uehara, Pablo Ventura, Xi Wang, WaheedHafez, Keiichi Watanabe, Watanabe, Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy
Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Zheng, Zheng, ZhUyU1997, and Zou Chang Wei.
ZhUyU1997, and Zou Chang Wei.
The code in the files that constitute xv6 is The code in the files that constitute xv6 is
Copyright 2006-2022 Frans Kaashoek, Robert Morris, and Russ Cox. Copyright 2006-2020 Frans Kaashoek, Robert Morris, and Russ Cox.
ERROR REPORTS ERROR REPORTS
Please send errors and suggestions to Frans Kaashoek and Robert Morris Please send errors and suggestions to Frans Kaashoek and Robert Morris
(kaashoek,rtm@mit.edu). The main purpose of xv6 is as a teaching (kaashoek,rtm@mit.edu). The main purpose of xv6 is as a teaching
operating system for MIT's 6.1810, so we are more interested in operating system for MIT's 6.S081, so we are more interested in
simplifications and clarifications than new features. simplifications and clarifications than new features.
BUILDING AND RUNNING XV6 BUILDING AND RUNNING XV6

View file

@ -136,7 +136,7 @@ char* strncpy(char*, const char*, int);
// syscall.c // syscall.c
void argint(int, int*); void argint(int, int*);
int argstr(int, char*, int); int argstr(int, char*, int);
void argaddr(int, uint64 *); void argaddr(int, uint64 *);
int fetchstr(uint64, char*, int); int fetchstr(uint64, char*, int);
int fetchaddr(uint64, uint64*); int fetchaddr(uint64, uint64*);
void syscall(); void syscall();

View file

@ -193,8 +193,7 @@ static struct inode* iget(uint dev, uint inum);
// Allocate an inode on device dev. // Allocate an inode on device dev.
// Mark it as allocated by giving it type type. // Mark it as allocated by giving it type type.
// Returns an unlocked but allocated and referenced inode, // Returns an unlocked but allocated and referenced inode.
// or NULL if there is no free inode.
struct inode* struct inode*
ialloc(uint dev, short type) ialloc(uint dev, short type)
{ {
@ -214,8 +213,7 @@ ialloc(uint dev, short type)
} }
brelse(bp); brelse(bp);
} }
printf("ialloc: no inodes\n"); panic("ialloc: no inodes");
return 0;
} }
// Copy a modified in-memory inode to disk. // Copy a modified in-memory inode to disk.

View file

@ -79,7 +79,6 @@ argstr(int n, char *buf, int max)
return fetchstr(addr, buf, max); return fetchstr(addr, buf, max);
} }
// Prototypes for the functions that handle system calls.
extern uint64 sys_fork(void); extern uint64 sys_fork(void);
extern uint64 sys_exit(void); extern uint64 sys_exit(void);
extern uint64 sys_wait(void); extern uint64 sys_wait(void);
@ -102,8 +101,6 @@ extern uint64 sys_link(void);
extern uint64 sys_mkdir(void); extern uint64 sys_mkdir(void);
extern uint64 sys_close(void); extern uint64 sys_close(void);
// An array mapping syscall numbers from syscall.h
// to the function that handles the system call.
static uint64 (*syscalls[])(void) = { static uint64 (*syscalls[])(void) = {
[SYS_fork] sys_fork, [SYS_fork] sys_fork,
[SYS_exit] sys_exit, [SYS_exit] sys_exit,
@ -136,8 +133,6 @@ syscall(void)
num = p->trapframe->a7; num = p->trapframe->a7;
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) { if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
// Use num to lookup the system call function for num, call it,
// and store its return value in p->trapframe->a0
p->trapframe->a0 = syscalls[num](); p->trapframe->a0 = syscalls[num]();
} else { } else {
printf("%d %s: unknown sys call %d\n", printf("%d %s: unknown sys call %d\n",

View file

@ -262,10 +262,8 @@ create(char *path, short type, short major, short minor)
return 0; return 0;
} }
if((ip = ialloc(dp->dev, type)) == 0){ if((ip = ialloc(dp->dev, type)) == 0)
iunlockput(dp); panic("create: ialloc");
return 0;
}
ilock(ip); ilock(ip);
ip->major = major; ip->major = major;

View file

@ -80,18 +80,9 @@ uservec:
# load the address of usertrap(), from p->trapframe->kernel_trap # load the address of usertrap(), from p->trapframe->kernel_trap
ld t0, 16(a0) ld t0, 16(a0)
# load the kernel page table, from p->trapframe->kernel_satp
# fetch the kernel page table address, from p->trapframe->kernel_satp.
ld t1, 0(a0) ld t1, 0(a0)
# wait for any previous memory operations to complete, so that
# they use the user page table.
sfence.vma zero, zero
# install the kernel page table.
csrw satp, t1 csrw satp, t1
# flush now-stale user entries from the TLB.
sfence.vma zero, zero sfence.vma zero, zero
# jump to usertrap(), which does not return # jump to usertrap(), which does not return
@ -105,7 +96,6 @@ userret:
# a0: user page table, for satp. # a0: user page table, for satp.
# switch to the user page table. # switch to the user page table.
sfence.vma zero, zero
csrw satp, a0 csrw satp, a0
sfence.vma zero, zero sfence.vma zero, zero

View file

@ -61,12 +61,7 @@ kvminit(void)
void void
kvminithart() kvminithart()
{ {
// wait for any previous writes to the page table memory to finish.
sfence_vma();
w_satp(MAKE_SATP(kernel_pagetable)); w_satp(MAKE_SATP(kernel_pagetable));
// flush stale entries from the TLB.
sfence_vma(); sfence_vma();
} }

View file

@ -305,7 +305,7 @@ iter()
exit(1); exit(1);
} }
if(pid1 == 0){ if(pid1 == 0){
rand_next ^= 31; rand_next = 31;
go(0); go(0);
exit(0); exit(0);
} }
@ -316,7 +316,7 @@ iter()
exit(1); exit(1);
} }
if(pid2 == 0){ if(pid2 == 0){
rand_next ^= 7177; rand_next = 7177;
go(1); go(1);
exit(0); exit(0);
} }
@ -346,6 +346,5 @@ main()
wait(0); wait(0);
} }
sleep(20); sleep(20);
rand_next += 1;
} }
} }

View file

@ -21,12 +21,6 @@
char buf[BUFSZ]; char buf[BUFSZ];
//
// Section with tests that run fairly quickly. Use -q if you want to
// run just those. With -q usertests also runs the ones that take a
// fair of time.
//
// what if you pass ridiculous pointers to system calls // what if you pass ridiculous pointers to system calls
// that read user memory with copyin? // that read user memory with copyin?
void void
@ -1518,6 +1512,46 @@ linkunlink(char *s)
exit(0); exit(0);
} }
// directory that uses indirect blocks
void
bigdir(char *s)
{
enum { N = 500 };
int i, fd;
char name[10];
unlink("bd");
fd = open("bd", O_CREATE);
if(fd < 0){
printf("%s: bigdir create failed\n", s);
exit(1);
}
close(fd);
for(i = 0; i < N; i++){
name[0] = 'x';
name[1] = '0' + (i / 64);
name[2] = '0' + (i % 64);
name[3] = '\0';
if(link("bd", name) != 0){
printf("%s: bigdir link(bd, %s) failed\n", s, name);
exit(1);
}
}
unlink("bd");
for(i = 0; i < N; i++){
name[0] = 'x';
name[1] = '0' + (i / 64);
name[2] = '0' + (i % 64);
name[3] = '\0';
if(unlink(name) != 0){
printf("%s: bigdir unlink failed", s);
exit(1);
}
}
}
void void
subdir(char *s) subdir(char *s)
@ -1724,6 +1758,59 @@ bigwrite(char *s)
} }
} }
// concurrent writes to try to provoke deadlock in the virtio disk
// driver.
void
manywrites(char *s)
{
int nchildren = 4;
int howmany = 30; // increase to look for deadlock
for(int ci = 0; ci < nchildren; ci++){
int pid = fork();
if(pid < 0){
printf("fork failed\n");
exit(1);
}
if(pid == 0){
char name[3];
name[0] = 'b';
name[1] = 'a' + ci;
name[2] = '\0';
unlink(name);
for(int iters = 0; iters < howmany; iters++){
for(int i = 0; i < ci+1; i++){
int fd = open(name, O_CREATE | O_RDWR);
if(fd < 0){
printf("%s: cannot create %s\n", s, name);
exit(1);
}
int sz = sizeof(buf);
int cc = write(fd, buf, sz);
if(cc != sz){
printf("%s: write(%d) ret %d\n", s, sz, cc);
exit(1);
}
close(fd);
}
unlink(name);
}
unlink(name);
exit(0);
}
}
for(int ci = 0; ci < nchildren; ci++){
int st = 0;
wait(&st);
if(st != 0)
exit(st);
}
exit(0);
}
void void
bigfile(char *s) bigfile(char *s)
@ -2555,189 +2642,6 @@ sbrk8000(char *s)
} }
// regression test. test whether exec() leaks memory if one of the
// arguments is invalid. the test passes if the kernel doesn't panic.
void
badarg(char *s)
{
for(int i = 0; i < 50000; i++){
char *argv[2];
argv[0] = (char*)0xffffffff;
argv[1] = 0;
exec("echo", argv);
}
exit(0);
}
struct test {
void (*f)(char *);
char *s;
} quicktests[] = {
{copyin, "copyin"},
{copyout, "copyout"},
{copyinstr1, "copyinstr1"},
{copyinstr2, "copyinstr2"},
{copyinstr3, "copyinstr3"},
{rwsbrk, "rwsbrk" },
{truncate1, "truncate1"},
{truncate2, "truncate2"},
{truncate3, "truncate3"},
{openiputtest, "openiput"},
{exitiputtest, "exitiput"},
{iputtest, "iput"},
{opentest, "opentest"},
{writetest, "writetest"},
{writebig, "writebig"},
{createtest, "createtest"},
{dirtest, "dirtest"},
{exectest, "exectest"},
{pipe1, "pipe1"},
{killstatus, "killstatus"},
{preempt, "preempt"},
{exitwait, "exitwait"},
{reparent, "reparent" },
{twochildren, "twochildren"},
{forkfork, "forkfork"},
{forkforkfork, "forkforkfork"},
{reparent2, "reparent2"},
{mem, "mem"},
{sharedfd, "sharedfd"},
{fourfiles, "fourfiles"},
{createdelete, "createdelete"},
{unlinkread, "unlinkread"},
{linktest, "linktest"},
{concreate, "concreate"},
{linkunlink, "linkunlink"},
{subdir, "subdir"},
{bigwrite, "bigwrite"},
{bigfile, "bigfile"},
{fourteen, "fourteen"},
{rmdot, "rmdot"},
{dirfile, "dirfile"},
{iref, "iref"},
{forktest, "forktest"},
{sbrkbasic, "sbrkbasic"},
{sbrkmuch, "sbrkmuch"},
{kernmem, "kernmem"},
{MAXVAplus, "MAXVAplus"},
{sbrkfail, "sbrkfail"},
{sbrkarg, "sbrkarg"},
{validatetest, "validatetest"},
{bsstest, "bsstest"},
{bigargtest, "bigargtest"},
{argptest, "argptest"},
{stacktest, "stacktest"},
{textwrite, "textwrite"},
{pgbug, "pgbug" },
{sbrkbugs, "sbrkbugs" },
{sbrklast, "sbrklast"},
{sbrk8000, "sbrk8000"},
{badarg, "badarg" },
{ 0, 0},
};
//
// Section with tests that take a fair bit of time
//
// directory that uses indirect blocks
void
bigdir(char *s)
{
enum { N = 500 };
int i, fd;
char name[10];
unlink("bd");
fd = open("bd", O_CREATE);
if(fd < 0){
printf("%s: bigdir create failed\n", s);
exit(1);
}
close(fd);
for(i = 0; i < N; i++){
name[0] = 'x';
name[1] = '0' + (i / 64);
name[2] = '0' + (i % 64);
name[3] = '\0';
if(link("bd", name) != 0){
printf("%s: bigdir link(bd, %s) failed\n", s, name);
exit(1);
}
}
unlink("bd");
for(i = 0; i < N; i++){
name[0] = 'x';
name[1] = '0' + (i / 64);
name[2] = '0' + (i % 64);
name[3] = '\0';
if(unlink(name) != 0){
printf("%s: bigdir unlink failed", s);
exit(1);
}
}
}
// concurrent writes to try to provoke deadlock in the virtio disk
// driver.
void
manywrites(char *s)
{
int nchildren = 4;
int howmany = 30; // increase to look for deadlock
for(int ci = 0; ci < nchildren; ci++){
int pid = fork();
if(pid < 0){
printf("fork failed\n");
exit(1);
}
if(pid == 0){
char name[3];
name[0] = 'b';
name[1] = 'a' + ci;
name[2] = '\0';
unlink(name);
for(int iters = 0; iters < howmany; iters++){
for(int i = 0; i < ci+1; i++){
int fd = open(name, O_CREATE | O_RDWR);
if(fd < 0){
printf("%s: cannot create %s\n", s, name);
exit(1);
}
int sz = sizeof(buf);
int cc = write(fd, buf, sz);
if(cc != sz){
printf("%s: write(%d) ret %d\n", s, sz, cc);
exit(1);
}
close(fd);
}
unlink(name);
}
unlink(name);
exit(0);
}
}
for(int ci = 0; ci < nchildren; ci++){
int st = 0;
wait(&st);
if(st != 0)
exit(st);
}
exit(0);
}
// regression test. does write() with an invalid buffer pointer cause // regression test. does write() with an invalid buffer pointer cause
// a block to be allocated for a file that is then not freed when the // a block to be allocated for a file that is then not freed when the
// file is deleted? if the kernel has this bug, it will panic: balloc: // file is deleted? if the kernel has this bug, it will panic: balloc:
@ -2775,6 +2679,21 @@ badwrite(char *s)
exit(0); exit(0);
} }
// regression test. test whether exec() leaks memory if one of the
// arguments is invalid. the test passes if the kernel doesn't panic.
void
badarg(char *s)
{
for(int i = 0; i < 50000; i++){
char *argv[2];
argv[0] = (char*)0xffffffff;
argv[1] = 0;
exec("echo", argv);
}
exit(0);
}
// test the exec() code that cleans up if it runs out // test the exec() code that cleans up if it runs out
// of memory. it's really a test that such a condition // of memory. it's really a test that such a condition
// doesn't cause a panic. // doesn't cause a panic.
@ -2831,7 +2750,6 @@ diskfull(char *s)
unlink(name); unlink(name);
int fd = open(name, O_CREATE|O_RDWR|O_TRUNC); int fd = open(name, O_CREATE|O_RDWR|O_TRUNC);
if(fd < 0){ if(fd < 0){
// oops, ran out of inodes before running out of blocks.
printf("%s: could not create file %s\n", s, name); printf("%s: could not create file %s\n", s, name);
done = 1; done = 1;
break; break;
@ -2849,8 +2767,7 @@ diskfull(char *s)
// now that there are no free blocks, test that dirlink() // now that there are no free blocks, test that dirlink()
// merely fails (doesn't panic) if it can't extend // merely fails (doesn't panic) if it can't extend
// directory content. one of these file creations // directory content.
// is expected to fail.
int nzz = 128; int nzz = 128;
for(int i = 0; i < nzz; i++){ for(int i = 0; i < nzz; i++){
char name[32]; char name[32];
@ -2861,15 +2778,14 @@ diskfull(char *s)
name[4] = '\0'; name[4] = '\0';
unlink(name); unlink(name);
int fd = open(name, O_CREATE|O_RDWR|O_TRUNC); int fd = open(name, O_CREATE|O_RDWR|O_TRUNC);
if(fd < 0) if(fd < 0){
printf("%s: could not create file %s\n", s, name);
break; break;
}
close(fd); close(fd);
} }
// this mkdir() is expected to fail. mkdir("diskfulldir");
if(mkdir("diskfulldir") == 0)
printf("%s: mkdir(diskfulldir) unexpectedly succeeded!\n");
unlink("diskfulldir"); unlink("diskfulldir");
for(int i = 0; i < nzz; i++){ for(int i = 0; i < nzz; i++){
@ -2893,91 +2809,6 @@ diskfull(char *s)
} }
} }
void
outofinodes(char *s)
{
int nzz = 32*32;
for(int i = 0; i < nzz; i++){
char name[32];
name[0] = 'z';
name[1] = 'z';
name[2] = '0' + (i / 32);
name[3] = '0' + (i % 32);
name[4] = '\0';
unlink(name);
int fd = open(name, O_CREATE|O_RDWR|O_TRUNC);
if(fd < 0){
// failure is eventually expected.
break;
}
close(fd);
}
for(int i = 0; i < nzz; i++){
char name[32];
name[0] = 'z';
name[1] = 'z';
name[2] = '0' + (i / 32);
name[3] = '0' + (i % 32);
name[4] = '\0';
unlink(name);
}
}
struct test slowtests[] = {
{bigdir, "bigdir"},
{manywrites, "manywrites"},
{badwrite, "badwrite" },
{execout, "execout"},
{diskfull, "diskfull"},
{outofinodes, "outofinodes"},
{ 0, 0},
};
//
// drive tests
//
// run each test in its own process. run returns 1 if child's exit()
// indicates success.
int
run(void f(char *), char *s) {
int pid;
int xstatus;
printf("test %s: ", s);
if((pid = fork()) < 0) {
printf("runtest: fork error\n");
exit(1);
}
if(pid == 0) {
f(s);
exit(0);
} else {
wait(&xstatus);
if(xstatus != 0)
printf("FAILED\n");
else
printf("OK\n");
return xstatus == 0;
}
}
int
runtests(struct test *tests, char *justone) {
for (struct test *t = tests; t->s != 0; t++) {
if((justone == 0) || strcmp(t->s, justone) == 0) {
if(!run(t->f, t->s)){
printf("SOME TESTS FAILED\n");
return 1;
}
}
}
return 0;
}
// //
// use sbrk() to count how many free physical memory pages there are. // use sbrk() to count how many free physical memory pages there are.
// touches the pages to force allocation. // touches the pages to force allocation.
@ -3044,58 +2875,165 @@ countfree()
return n; return n;
} }
// run each test in its own process. run returns 1 if child's exit()
// indicates success.
int int
drivetests(int quick, int continuous, char *justone) { run(void f(char *), char *s) {
do { int pid;
printf("usertests starting\n"); int xstatus;
int free0 = countfree();
int free1 = 0; printf("test %s: ", s);
if (runtests(quicktests, justone)) { if((pid = fork()) < 0) {
if(continuous != 2) { printf("runtest: fork error\n");
return 1; exit(1);
} }
} if(pid == 0) {
if(!quick) { f(s);
if (justone == 0) exit(0);
printf("usertests slow tests starting\n"); } else {
if (runtests(slowtests, justone)) { wait(&xstatus);
if(continuous != 2) { if(xstatus != 0)
return 1; printf("FAILED\n");
} else
} printf("OK\n");
} return xstatus == 0;
if((free1 = countfree()) < free0) { }
printf("FAILED -- lost some free pages %d (out of %d)\n", free1, free0);
if(continuous != 2) {
return 1;
}
}
} while(continuous);
return 0;
} }
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int continuous = 0; int continuous = 0;
int quick = 0;
char *justone = 0; char *justone = 0;
if(argc == 2 && strcmp(argv[1], "-q") == 0){ if(argc == 2 && strcmp(argv[1], "-c") == 0){
quick = 1;
} else if(argc == 2 && strcmp(argv[1], "-c") == 0){
continuous = 1; continuous = 1;
} else if(argc == 2 && strcmp(argv[1], "-C") == 0){ } else if(argc == 2 && strcmp(argv[1], "-C") == 0){
continuous = 2; continuous = 2;
} else if(argc == 2 && argv[1][0] != '-'){ } else if(argc == 2 && argv[1][0] != '-'){
justone = argv[1]; justone = argv[1];
} else if(argc > 1){ } else if(argc > 1){
printf("Usage: usertests [-c] [-C] [-q] [testname]\n"); printf("Usage: usertests [-c] [testname]\n");
exit(1); exit(1);
} }
if (drivetests(quick, continuous, justone)) {
exit(1); struct test {
void (*f)(char *);
char *s;
} tests[] = {
{copyin, "copyin"},
{copyout, "copyout"},
{copyinstr1, "copyinstr1"},
{copyinstr2, "copyinstr2"},
{copyinstr3, "copyinstr3"},
{rwsbrk, "rwsbrk" },
{truncate1, "truncate1"},
{truncate2, "truncate2"},
{truncate3, "truncate3"},
{openiputtest, "openiput"},
{exitiputtest, "exitiput"},
{iputtest, "iput"},
{opentest, "opentest"},
{writetest, "writetest"},
{writebig, "writebig"},
{createtest, "createtest"},
{dirtest, "dirtest"},
{exectest, "exectest"},
{pipe1, "pipe1"},
{killstatus, "killstatus"},
{preempt, "preempt"},
{exitwait, "exitwait"},
{reparent, "reparent" },
{twochildren, "twochildren"},
{forkfork, "forkfork"},
{forkforkfork, "forkforkfork"},
{reparent2, "reparent2"},
{mem, "mem"},
{sharedfd, "sharedfd"},
{fourfiles, "fourfiles"},
{createdelete, "createdelete"},
{unlinkread, "unlinkread"},
{linktest, "linktest"},
{concreate, "concreate"},
{linkunlink, "linkunlink"},
{bigdir, "bigdir"}, // slow
{subdir, "subdir"},
{bigwrite, "bigwrite"},
{manywrites, "manywrites"},
{bigfile, "bigfile"},
{fourteen, "fourteen"},
{rmdot, "rmdot"},
{dirfile, "dirfile"},
{iref, "iref"},
{forktest, "forktest"},
{sbrkbasic, "sbrkbasic"},
{sbrkmuch, "sbrkmuch"},
{kernmem, "kernmem"},
{MAXVAplus, "MAXVAplus"},
{sbrkfail, "sbrkfail"},
{sbrkarg, "sbrkarg"},
{validatetest, "validatetest"},
{bsstest, "bsstest"},
{bigargtest, "bigargtest"},
{argptest, "argptest"},
{stacktest, "stacktest"},
{textwrite, "textwrite"},
{pgbug, "pgbug" },
{sbrkbugs, "sbrkbugs" },
{sbrklast, "sbrklast"},
{sbrk8000, "sbrk8000"},
{badwrite, "badwrite" },
{badarg, "badarg" },
{execout, "execout"},
{diskfull, "diskfull"},
{ 0, 0},
};
if(continuous){
printf("continuous usertests starting\n");
while(1){
int fail = 0;
int free0 = countfree();
for (struct test *t = tests; t->s != 0; t++) {
if(!run(t->f, t->s)){
fail = 1;
break;
}
}
if(fail){
printf("SOME TESTS FAILED\n");
if(continuous != 2)
exit(1);
}
int free1 = countfree();
if(free1 < free0){
printf("FAILED -- lost %d free pages\n", free0 - free1);
if(continuous != 2)
exit(1);
}
}
}
printf("usertests starting\n");
int free0 = countfree();
int free1 = 0;
int fail = 0;
for (struct test *t = tests; t->s != 0; t++) {
if((justone == 0) || strcmp(t->s, justone) == 0) {
if(!run(t->f, t->s))
fail = 1;
}
}
if(fail){
printf("SOME TESTS FAILED\n");
exit(1);
} else if((free1 = countfree()) < free0){
printf("FAILED -- lost some free pages %d (out of %d)\n", free1, free0);
exit(1);
} else {
printf("ALL TESTS PASSED\n");
exit(0);
} }
printf("ALL TESTS PASSED\n");
exit(0);
} }