xv6-riscv-rust/user/grind.c

341 lines
6.9 KiB
C

//
// run random system calls in parallel forever.
//
#include "kernel/param.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
#include "kernel/fcntl.h"
#include "kernel/syscall.h"
#include "kernel/memlayout.h"
#include "kernel/riscv.h"
// from FreeBSD.
int do_rand(unsigned long *ctx) {
/*
* Compute x = (7^5 * x) mod (2^31 - 1)
* without overflowing 31 bits:
* (2^31 - 1) = 127773 * (7^5) + 2836
* From "Random number generators: good ones are hard to find",
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
* October 1988, p. 1195.
*/
long hi, lo, x;
/* Transform to [1, 0x7ffffffe] range. */
x = (*ctx % 0x7ffffffe) + 1;
hi = x / 127773;
lo = x % 127773;
x = 16807 * lo - 2836 * hi;
if (x < 0)
x += 0x7fffffff;
/* Transform to [0, 0x7ffffffd] range. */
x--;
*ctx = x;
return (x);
}
unsigned long rand_next = 1;
int rand(void) { return (do_rand(&rand_next)); }
void go(int which_child) {
int fd = -1;
static char buf[999];
char *break0 = sbrk(0);
uint64 iters = 0;
mkdir("grindir");
if (chdir("grindir") != 0) {
printf("grind: chdir grindir failed\n");
exit(1);
}
chdir("/");
while (1) {
iters++;
if ((iters % 500) == 0)
write(1, which_child ? "B" : "A", 1);
int what = rand() % 23;
if (what == 1) {
close(open("grindir/../a", O_CREATE | O_RDWR));
} else if (what == 2) {
close(open("grindir/../grindir/../b", O_CREATE | O_RDWR));
} else if (what == 3) {
unlink("grindir/../a");
} else if (what == 4) {
if (chdir("grindir") != 0) {
printf("grind: chdir grindir failed\n");
exit(1);
}
unlink("../b");
chdir("/");
} else if (what == 5) {
close(fd);
fd = open("/grindir/../a", O_CREATE | O_RDWR);
} else if (what == 6) {
close(fd);
fd = open("/./grindir/./../b", O_CREATE | O_RDWR);
} else if (what == 7) {
write(fd, buf, sizeof(buf));
} else if (what == 8) {
read(fd, buf, sizeof(buf));
} else if (what == 9) {
mkdir("grindir/../a");
close(open("a/../a/./a", O_CREATE | O_RDWR));
unlink("a/a");
} else if (what == 10) {
mkdir("/../b");
close(open("grindir/../b/b", O_CREATE | O_RDWR));
unlink("b/b");
} else if (what == 11) {
unlink("b");
link("../grindir/./../a", "../b");
} else if (what == 12) {
unlink("../grindir/../a");
link(".././b", "/grindir/../a");
} else if (what == 13) {
int pid = fork();
if (pid == 0) {
exit(0);
} else if (pid < 0) {
printf("grind: fork failed\n");
exit(1);
}
wait(0);
} else if (what == 14) {
int pid = fork();
if (pid == 0) {
fork();
fork();
exit(0);
} else if (pid < 0) {
printf("grind: fork failed\n");
exit(1);
}
wait(0);
} else if (what == 15) {
sbrk(6011);
} else if (what == 16) {
if (sbrk(0) > break0)
sbrk(-(sbrk(0) - break0));
} else if (what == 17) {
int pid = fork();
if (pid == 0) {
close(open("a", O_CREATE | O_RDWR));
exit(0);
} else if (pid < 0) {
printf("grind: fork failed\n");
exit(1);
}
if (chdir("../grindir/..") != 0) {
printf("grind: chdir failed\n");
exit(1);
}
kill(pid);
wait(0);
} else if (what == 18) {
int pid = fork();
if (pid == 0) {
kill(getpid());
exit(0);
} else if (pid < 0) {
printf("grind: fork failed\n");
exit(1);
}
wait(0);
} else if (what == 19) {
int fds[2];
if (pipe(fds) < 0) {
printf("grind: pipe failed\n");
exit(1);
}
int pid = fork();
if (pid == 0) {
fork();
fork();
if (write(fds[1], "x", 1) != 1)
printf("grind: pipe write failed\n");
char c;
if (read(fds[0], &c, 1) != 1)
printf("grind: pipe read failed\n");
exit(0);
} else if (pid < 0) {
printf("grind: fork failed\n");
exit(1);
}
close(fds[0]);
close(fds[1]);
wait(0);
} else if (what == 20) {
int pid = fork();
if (pid == 0) {
unlink("a");
mkdir("a");
chdir("a");
unlink("../a");
fd = open("x", O_CREATE | O_RDWR);
unlink("x");
exit(0);
} else if (pid < 0) {
printf("grind: fork failed\n");
exit(1);
}
wait(0);
} else if (what == 21) {
unlink("c");
// should always succeed. check that there are free i-nodes,
// file descriptors, blocks.
int fd1 = open("c", O_CREATE | O_RDWR);
if (fd1 < 0) {
printf("grind: create c failed\n");
exit(1);
}
if (write(fd1, "x", 1) != 1) {
printf("grind: write c failed\n");
exit(1);
}
struct stat st;
if (fstat(fd1, &st) != 0) {
printf("grind: fstat failed\n");
exit(1);
}
if (st.size != 1) {
printf("grind: fstat reports wrong size %d\n", (int)st.size);
exit(1);
}
if (st.ino > 200) {
printf("grind: fstat reports crazy i-number %d\n", st.ino);
exit(1);
}
close(fd1);
unlink("c");
} else if (what == 22) {
// echo hi | cat
int aa[2], bb[2];
if (pipe(aa) < 0) {
fprintf(2, "grind: pipe failed\n");
exit(1);
}
if (pipe(bb) < 0) {
fprintf(2, "grind: pipe failed\n");
exit(1);
}
int pid1 = fork();
if (pid1 == 0) {
close(bb[0]);
close(bb[1]);
close(aa[0]);
close(1);
if (dup(aa[1]) != 1) {
fprintf(2, "grind: dup failed\n");
exit(1);
}
close(aa[1]);
char *args[3] = {"echo", "hi", 0};
exec("grindir/../echo", args);
fprintf(2, "grind: echo: not found\n");
exit(2);
} else if (pid1 < 0) {
fprintf(2, "grind: fork failed\n");
exit(3);
}
int pid2 = fork();
if (pid2 == 0) {
close(aa[1]);
close(bb[0]);
close(0);
if (dup(aa[0]) != 0) {
fprintf(2, "grind: dup failed\n");
exit(4);
}
close(aa[0]);
close(1);
if (dup(bb[1]) != 1) {
fprintf(2, "grind: dup failed\n");
exit(5);
}
close(bb[1]);
char *args[2] = {"cat", 0};
exec("/cat", args);
fprintf(2, "grind: cat: not found\n");
exit(6);
} else if (pid2 < 0) {
fprintf(2, "grind: fork failed\n");
exit(7);
}
close(aa[0]);
close(aa[1]);
close(bb[1]);
char buf[4] = {0, 0, 0, 0};
read(bb[0], buf + 0, 1);
read(bb[0], buf + 1, 1);
read(bb[0], buf + 2, 1);
close(bb[0]);
int st1, st2;
wait(&st1);
wait(&st2);
if (st1 != 0 || st2 != 0 || strcmp(buf, "hi\n") != 0) {
printf("grind: exec pipeline failed %d %d \"%s\"\n", st1, st2,
buf);
exit(1);
}
}
}
}
void iter() {
unlink("a");
unlink("b");
int pid1 = fork();
if (pid1 < 0) {
printf("grind: fork failed\n");
exit(1);
}
if (pid1 == 0) {
rand_next ^= 31;
go(0);
exit(0);
}
int pid2 = fork();
if (pid2 < 0) {
printf("grind: fork failed\n");
exit(1);
}
if (pid2 == 0) {
rand_next ^= 7177;
go(1);
exit(0);
}
int st1 = -1;
wait(&st1);
if (st1 != 0) {
kill(pid1);
kill(pid2);
}
int st2 = -1;
wait(&st2);
exit(0);
}
int main() {
while (1) {
int pid = fork();
if (pid == 0) {
iter();
exit(0);
}
if (pid > 0) {
wait(0);
}
sleep(20);
rand_next += 1;
}
}