#include #include #include #include #include #define MAX_PIPES 450 #define FORK_CYCLES 2000000 #define CLOSE_CYCLES 100000 #define STAT_SHIFT 6 static inline unsigned long readtsc() { unsigned int low, high; asm volatile("rdtsc" : "=a" (low), "=d" (high)); return low | ((unsigned long)(high) << 32); } static int pipefd[MAX_PIPES][2]; int main(int argc, char *argv[]) { unsigned long loop, race_start, miss; unsigned long misses = 0, races = 0; int i; pid_t pid; struct rlimit rlim = { .rlim_cur = MAX_PIPES * 2 + 96, .rlim_max = MAX_PIPES * 2 + 96, }; if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) perror("setrlimit(RLIMIT_NOFILE)"); for (loop = 1;;loop++) { /* * Make a bunch of pipes */ for (i = 0;i < MAX_PIPES;i++) { if (pipe(pipefd[i]) == -1) { perror("pipe()"); exit(EXIT_FAILURE); } } race_start = readtsc() + FORK_CYCLES; asm("":::"memory"); pid = fork(); if (pid == -1) { perror("fork()"); exit(EXIT_FAILURE); } pid = !!pid; /* * Close one pipe descriptor per process */ for (i = 0;i < MAX_PIPES;i++) close(pipefd[i][!pid]); for (i = 0;i < MAX_PIPES;i++) { /* * Line up and try to close at the same time */ miss = 1; while (readtsc() < race_start) miss = 0; close(pipefd[i][pid]); misses+= miss; race_start+= CLOSE_CYCLES; } races+= MAX_PIPES; if (!(loop & (~(~0UL << STAT_SHIFT)))) fprintf(stderr, "%c %lu (%.2f%% false starts)\n", "CP"[pid], readtsc(), misses * 100. / races); if (pid) wait(NULL); /* Parent */ else exit(0); /* Child */ } }