#include void umain(int argc, char **argv) { int p[2], r, pid, i, max; void *va; struct Fd *fd; const volatile struct Env *kid; cprintf("testing for dup race...\n"); if ((r = pipe(p)) < 0) panic("pipe: %e", r); max = 200; if ((r = fork()) < 0) panic("fork: %e", r); if (r == 0) { close(p[1]); // // Now the ref count for p[0] will toggle between 2 and 3 // as the parent dups and closes it (there's a close implicit in dup). // // The ref count for p[1] is 1. // Thus the ref count for the underlying pipe structure // will toggle between 3 and 4. // // If a clock interrupt catches close between unmapping // the pipe structure and unmapping the fd, we'll have // a ref count for p[0] of 3, a ref count for p[1] of 1, // and a ref count for the pipe structure of 3, which is // a no-no. // // If a clock interrupt catches dup between mapping the // fd and mapping the pipe structure, we'll have the same // ref counts, still a no-no. // for (i=0; ienv_status == ENV_RUNNABLE) dup(p[0], 10); cprintf("child done with loop\n"); if (pipeisclosed(p[0])) panic("somehow the other end of p[0] got closed!"); if ((r = fd_lookup(p[0], &fd)) < 0) panic("cannot look up p[0]: %e", r); va = fd2data(fd); if (pageref(va) != 3+1) cprintf("\nchild detected race\n"); else cprintf("\nrace didn't happen\n", max); }