// // 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; } }