Compare commits

...

10 commits

Author SHA1 Message Date
Frans Kaashoek
f5b93ef12f Update acks
61810
2022-08-25 14:20:52 -04:00
Frans Kaashoek
3d6ce9b308 Separate tests in slow and quick. The slow tests run xv6 out of
memory, out of disk space, or test big directories.

Support -q option to run only the quick tests, which saves about
7mins.

Clean up driver by removing duplicated code.
2022-08-25 09:45:35 -04:00
Robert Morris
ed101befee comment the sfences 2022-08-24 13:47:47 -04:00
Robert Morris
581bc4cbd1 sfence before enabling paging 2022-08-24 13:42:59 -04:00
Robert Morris
29ce3161f8 Merge branch 'riscv' of g.csail.mit.edu:xv6-dev into riscv 2022-08-24 13:24:37 -04:00
Robert Morris
9c1b8a4eb0 sfence before writing satp, as well as after 2022-08-24 13:24:24 -04:00
Frans Kaashoek
cc486ddee0 Help students read this C syntax 2022-08-24 08:57:56 -04:00
Robert Morris
96047832c6 Merge branch 'riscv' of g.csail.mit.edu:xv6-dev into riscv 2022-08-23 12:26:39 -04:00
Robert Morris
7c1810e1ae tolerate running out of inodes 2022-08-23 12:26:26 -04:00
Frans Kaashoek
ac8c0bb177 x 2022-08-23 11:56:29 -04:00
9 changed files with 369 additions and 280 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.828/, which provides 2000)). See also https://pdos.csail.mit.edu/6.1810/, 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,29 +14,31 @@ 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, Ian Chen, Dan Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, carlclone, Ian
Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi, eyalz800, Nelson Chen, Dan Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi,
Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel Filardo, flespark, eyalz800, Nelson Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel
Peter Froehlich, Yakir Goaron, Shivam Handa, Matt Harvey, Bryan Henry, Filardo, flespark, Peter Froehlich, Yakir Goaron, Shivam Handa, Matt
jaichenhengjie, Jim Huang, Matúš Jókay, Alexander Kapshuk, Anders Harvey, Bryan Henry, jaichenhengjie, Jim Huang, Matúš Jókay, John
Kaseorg, kehao95, Wolfgang Keller, Jungwoo Kim, Jonathan Kimmitt, Jolly, Alexander Kapshuk, Anders Kaseorg, kehao95, Wolfgang Keller,
Eddie Kohler, Vadim Kolontsov, Austin Liew, l0stman, Pavan Jungwoo Kim, Jonathan Kimmitt, Eddie Kohler, Vadim Kolontsov, Austin
Maddamsetti, Imbar Marinescu, Yandong Mao, Matan Shabtay, Hitoshi Liew, l0stman, Pavan Maddamsetti, Imbar Marinescu, Yandong Mao, Matan
Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel Nider, Shabtay, Hitoshi Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel
OptimisticSide, Greg Price, Jude Rich, Ayan Shafqat, Eldar Sehayek, Nider, Hayato Ohhashi, OptimisticSide, Harry Porter, Greg Price, Jude
Yongming Shen, Fumiya Shigemitsu, Cam Tenny, tyfkda, Warren Toomey, Rich, segfault, Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya
Stephen Tu, Rafael Ubal, Amane Uehara, Pablo Ventura, Xi Wang, Keiichi Shigemitsu, Cam Tenny, tyfkda, Warren Toomey, Stephen Tu, Rafael Ubal,
Watanabe, Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Amane Uehara, Pablo Ventura, Xi Wang, WaheedHafez, Keiichi Watanabe,
Zheng, ZhUyU1997, and Zou Chang Wei. Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Zheng,
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-2020 Frans Kaashoek, Robert Morris, and Russ Cox. Copyright 2006-2022 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.S081, so we are more interested in operating system for MIT's 6.1810, 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

@ -193,7 +193,8 @@ 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)
{ {
@ -213,7 +214,8 @@ ialloc(uint dev, short type)
} }
brelse(bp); brelse(bp);
} }
panic("ialloc: no inodes"); printf("ialloc: no inodes\n");
return 0;
} }
// Copy a modified in-memory inode to disk. // Copy a modified in-memory inode to disk.

View file

@ -79,6 +79,7 @@ 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);
@ -101,6 +102,8 @@ 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,
@ -133,6 +136,8 @@ 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,8 +262,10 @@ 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){
panic("create: ialloc"); iunlockput(dp);
return 0;
}
ilock(ip); ilock(ip);
ip->major = major; ip->major = major;

View file

@ -80,9 +80,18 @@ 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
@ -96,6 +105,7 @@ 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,7 +61,12 @@ 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,5 +346,6 @@ main()
wait(0); wait(0);
} }
sleep(20); sleep(20);
rand_next += 1;
} }
} }

View file

@ -21,6 +21,12 @@
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
@ -1512,46 +1518,6 @@ 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)
@ -1758,59 +1724,6 @@ 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)
@ -2642,6 +2555,189 @@ 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:
@ -2679,21 +2775,6 @@ 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.
@ -2750,6 +2831,7 @@ 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;
@ -2767,7 +2849,8 @@ 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. // directory content. one of these file creations
// 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];
@ -2778,14 +2861,15 @@ 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);
} }
mkdir("diskfulldir"); // this mkdir() is expected to fail.
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++){
@ -2809,6 +2893,91 @@ 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.
@ -2875,165 +3044,58 @@ countfree()
return n; return n;
} }
// run each test in its own process. run returns 1 if child's exit()
// indicates success.
int int
run(void f(char *), char *s) { drivetests(int quick, int continuous, char *justone) {
int pid; do {
int xstatus; printf("usertests starting\n");
int free0 = countfree();
printf("test %s: ", s); int free1 = 0;
if((pid = fork()) < 0) { if (runtests(quicktests, justone)) {
printf("runtest: fork error\n"); if(continuous != 2) {
exit(1); return 1;
} }
if(pid == 0) {
f(s);
exit(0);
} else {
wait(&xstatus);
if(xstatus != 0)
printf("FAILED\n");
else
printf("OK\n");
return xstatus == 0;
} }
if(!quick) {
if (justone == 0)
printf("usertests slow tests starting\n");
if (runtests(slowtests, justone)) {
if(continuous != 2) {
return 1;
}
}
}
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], "-c") == 0){ if(argc == 2 && strcmp(argv[1], "-q") == 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] [testname]\n"); printf("Usage: usertests [-c] [-C] [-q] [testname]\n");
exit(1); exit(1);
} }
if (drivetests(quick, continuous, justone)) {
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); 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"); printf("ALL TESTS PASSED\n");
exit(0); exit(0);
} }
}