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