Compare commits
10 commits
948cfbdb1f
...
f5b93ef12f
Author | SHA1 | Date | |
---|---|---|---|
f5b93ef12f | |||
3d6ce9b308 | |||
ed101befee | |||
581bc4cbd1 | |||
29ce3161f8 | |||
9c1b8a4eb0 | |||
cc486ddee0 | |||
96047832c6 | |||
7c1810e1ae | |||
ac8c0bb177 |
36
README
36
README
|
@ -6,7 +6,7 @@ ACKNOWLEDGMENTS
|
|||
|
||||
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,
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
We are also grateful for the bug reports and patches contributed by
|
||||
Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, Ian Chen, Dan
|
||||
Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi, eyalz800, Nelson
|
||||
Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel Filardo, flespark,
|
||||
Peter Froehlich, Yakir Goaron, Shivam Handa, Matt Harvey, Bryan Henry,
|
||||
jaichenhengjie, Jim Huang, Matúš Jókay, Alexander Kapshuk, Anders
|
||||
Kaseorg, kehao95, Wolfgang Keller, Jungwoo Kim, Jonathan Kimmitt,
|
||||
Eddie Kohler, Vadim Kolontsov, Austin Liew, l0stman, Pavan
|
||||
Maddamsetti, Imbar Marinescu, Yandong Mao, Matan Shabtay, Hitoshi
|
||||
Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel Nider,
|
||||
OptimisticSide, Greg Price, Jude Rich, Ayan Shafqat, Eldar Sehayek,
|
||||
Yongming Shen, Fumiya Shigemitsu, Cam Tenny, tyfkda, Warren Toomey,
|
||||
Stephen Tu, Rafael Ubal, Amane Uehara, Pablo Ventura, Xi Wang, Keiichi
|
||||
Watanabe, Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy
|
||||
Zheng, ZhUyU1997, and Zou Chang Wei.
|
||||
Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, carlclone, Ian
|
||||
Chen, Dan Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi,
|
||||
eyalz800, Nelson Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel
|
||||
Filardo, flespark, Peter Froehlich, Yakir Goaron, Shivam Handa, Matt
|
||||
Harvey, Bryan Henry, jaichenhengjie, Jim Huang, Matúš Jókay, John
|
||||
Jolly, Alexander Kapshuk, Anders Kaseorg, kehao95, Wolfgang Keller,
|
||||
Jungwoo Kim, Jonathan Kimmitt, Eddie Kohler, Vadim Kolontsov, Austin
|
||||
Liew, l0stman, Pavan Maddamsetti, Imbar Marinescu, Yandong Mao, Matan
|
||||
Shabtay, Hitoshi Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel
|
||||
Nider, Hayato Ohhashi, OptimisticSide, Harry Porter, Greg Price, Jude
|
||||
Rich, segfault, Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya
|
||||
Shigemitsu, Cam Tenny, tyfkda, Warren Toomey, Stephen Tu, Rafael Ubal,
|
||||
Amane Uehara, Pablo Ventura, Xi Wang, WaheedHafez, Keiichi Watanabe,
|
||||
Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Zheng,
|
||||
ZhUyU1997, and Zou Chang Wei.
|
||||
|
||||
|
||||
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
|
||||
|
||||
Please send errors and suggestions to Frans Kaashoek and Robert Morris
|
||||
(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.
|
||||
|
||||
BUILDING AND RUNNING XV6
|
||||
|
|
|
@ -136,7 +136,7 @@ char* strncpy(char*, const char*, int);
|
|||
// syscall.c
|
||||
void argint(int, int*);
|
||||
int argstr(int, char*, int);
|
||||
void argaddr(int, uint64 *);
|
||||
void argaddr(int, uint64 *);
|
||||
int fetchstr(uint64, char*, int);
|
||||
int fetchaddr(uint64, uint64*);
|
||||
void syscall();
|
||||
|
|
|
@ -193,7 +193,8 @@ static struct inode* iget(uint dev, uint inum);
|
|||
|
||||
// Allocate an inode on device dev.
|
||||
// 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*
|
||||
ialloc(uint dev, short type)
|
||||
{
|
||||
|
@ -213,7 +214,8 @@ ialloc(uint dev, short type)
|
|||
}
|
||||
brelse(bp);
|
||||
}
|
||||
panic("ialloc: no inodes");
|
||||
printf("ialloc: no inodes\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copy a modified in-memory inode to disk.
|
||||
|
|
|
@ -79,6 +79,7 @@ argstr(int n, char *buf, int max)
|
|||
return fetchstr(addr, buf, max);
|
||||
}
|
||||
|
||||
// Prototypes for the functions that handle system calls.
|
||||
extern uint64 sys_fork(void);
|
||||
extern uint64 sys_exit(void);
|
||||
extern uint64 sys_wait(void);
|
||||
|
@ -101,6 +102,8 @@ extern uint64 sys_link(void);
|
|||
extern uint64 sys_mkdir(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) = {
|
||||
[SYS_fork] sys_fork,
|
||||
[SYS_exit] sys_exit,
|
||||
|
@ -133,6 +136,8 @@ syscall(void)
|
|||
|
||||
num = p->trapframe->a7;
|
||||
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]();
|
||||
} else {
|
||||
printf("%d %s: unknown sys call %d\n",
|
||||
|
|
|
@ -262,8 +262,10 @@ create(char *path, short type, short major, short minor)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if((ip = ialloc(dp->dev, type)) == 0)
|
||||
panic("create: ialloc");
|
||||
if((ip = ialloc(dp->dev, type)) == 0){
|
||||
iunlockput(dp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ilock(ip);
|
||||
ip->major = major;
|
||||
|
|
|
@ -80,9 +80,18 @@ uservec:
|
|||
# load the address of usertrap(), from p->trapframe->kernel_trap
|
||||
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)
|
||||
|
||||
# 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
|
||||
|
||||
# flush now-stale user entries from the TLB.
|
||||
sfence.vma zero, zero
|
||||
|
||||
# jump to usertrap(), which does not return
|
||||
|
@ -96,6 +105,7 @@ userret:
|
|||
# a0: user page table, for satp.
|
||||
|
||||
# switch to the user page table.
|
||||
sfence.vma zero, zero
|
||||
csrw satp, a0
|
||||
sfence.vma zero, zero
|
||||
|
||||
|
|
|
@ -61,7 +61,12 @@ kvminit(void)
|
|||
void
|
||||
kvminithart()
|
||||
{
|
||||
// wait for any previous writes to the page table memory to finish.
|
||||
sfence_vma();
|
||||
|
||||
w_satp(MAKE_SATP(kernel_pagetable));
|
||||
|
||||
// flush stale entries from the TLB.
|
||||
sfence_vma();
|
||||
}
|
||||
|
||||
|
|
|
@ -305,7 +305,7 @@ iter()
|
|||
exit(1);
|
||||
}
|
||||
if(pid1 == 0){
|
||||
rand_next = 31;
|
||||
rand_next ^= 31;
|
||||
go(0);
|
||||
exit(0);
|
||||
}
|
||||
|
@ -316,7 +316,7 @@ iter()
|
|||
exit(1);
|
||||
}
|
||||
if(pid2 == 0){
|
||||
rand_next = 7177;
|
||||
rand_next ^= 7177;
|
||||
go(1);
|
||||
exit(0);
|
||||
}
|
||||
|
@ -346,5 +346,6 @@ main()
|
|||
wait(0);
|
||||
}
|
||||
sleep(20);
|
||||
rand_next += 1;
|
||||
}
|
||||
}
|
||||
|
|
572
user/usertests.c
572
user/usertests.c
|
@ -21,6 +21,12 @@
|
|||
|
||||
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
|
||||
// that read user memory with copyin?
|
||||
void
|
||||
|
@ -1512,46 +1518,6 @@ linkunlink(char *s)
|
|||
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
|
||||
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
|
||||
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
|
||||
// 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:
|
||||
|
@ -2679,21 +2775,6 @@ badwrite(char *s)
|
|||
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
|
||||
// of memory. it's really a test that such a condition
|
||||
// doesn't cause a panic.
|
||||
|
@ -2750,6 +2831,7 @@ diskfull(char *s)
|
|||
unlink(name);
|
||||
int fd = open(name, O_CREATE|O_RDWR|O_TRUNC);
|
||||
if(fd < 0){
|
||||
// oops, ran out of inodes before running out of blocks.
|
||||
printf("%s: could not create file %s\n", s, name);
|
||||
done = 1;
|
||||
break;
|
||||
|
@ -2767,7 +2849,8 @@ diskfull(char *s)
|
|||
|
||||
// now that there are no free blocks, test that dirlink()
|
||||
// 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;
|
||||
for(int i = 0; i < nzz; i++){
|
||||
char name[32];
|
||||
|
@ -2778,14 +2861,15 @@ diskfull(char *s)
|
|||
name[4] = '\0';
|
||||
unlink(name);
|
||||
int fd = open(name, O_CREATE|O_RDWR|O_TRUNC);
|
||||
if(fd < 0){
|
||||
printf("%s: could not create file %s\n", s, name);
|
||||
if(fd < 0)
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
mkdir("diskfulldir");
|
||||
// this mkdir() is expected to fail.
|
||||
if(mkdir("diskfulldir") == 0)
|
||||
printf("%s: mkdir(diskfulldir) unexpectedly succeeded!\n");
|
||||
|
||||
unlink("diskfulldir");
|
||||
|
||||
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.
|
||||
// touches the pages to force allocation.
|
||||
|
@ -2875,165 +3044,58 @@ countfree()
|
|||
return n;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
drivetests(int quick, int continuous, char *justone) {
|
||||
do {
|
||||
printf("usertests starting\n");
|
||||
int free0 = countfree();
|
||||
int free1 = 0;
|
||||
if (runtests(quicktests, justone)) {
|
||||
if(continuous != 2) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
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
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int continuous = 0;
|
||||
int quick = 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;
|
||||
} else if(argc == 2 && strcmp(argv[1], "-C") == 0){
|
||||
continuous = 2;
|
||||
} else if(argc == 2 && argv[1][0] != '-'){
|
||||
justone = argv[1];
|
||||
} else if(argc > 1){
|
||||
printf("Usage: usertests [-c] [testname]\n");
|
||||
printf("Usage: usertests [-c] [-C] [-q] [testname]\n");
|
||||
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");
|
||||
if (drivetests(quick, continuous, justone)) {
|
||||
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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue