DF-5436 / hx5436_race.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | /* * DF-5436 racer -- two CPU-pinned processes hammer open()/close() on the * two cdevs of one softc (the /dev/ulpt0 vs /dev/unlpt0 pair), same * direction (O_RDONLY -- the direction unprivileged users can reach on * the 0644 production nodes). * * The barrier/threaded variant serializes on one CPU under the DFly * scheduler; two pinned free-running processes give true concurrency * through the production gate window (gate check -> kmalloc(2x32KB) -> * sc_fflags |= at ulpt.c:427-456). * * The authoritative anomaly oracle is the KERNEL counter * hw.hx5436.opens_while_open ("successful open of a direction that is * already open" -- impossible when the gate is correct) plus * double_open_simul (both opens inside the race window simultaneously). * * usage: hx5436_race [seconds] */ #include <sys/types.h> #include <sys/sysctl.h> #include <sys/usched.h> #include <sys/wait.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> #include <errno.h> #define DEVA "/dev/hx5436a" #define DEVB "/dev/hx5436b" #define STOPF "/tmp/hx5436.stop" static double now_sec(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (ts.tv_sec + ts.tv_nsec / 1e9); } static int sysctl_int(const char *name) { int v = 0; size_t l = sizeof(v); if (sysctlbyname(name, &v, &l, NULL, 0) != 0) return (-1); return (v); } static void pin_cpu(int cpu) { if (usched_set(0, USCHED_SET_CPU, &cpu, sizeof(cpu)) != 0) fprintf(stderr, "[pin %d] usched_set: %s\n", cpu, strerror(errno)); } static void hammer(const char *dev, int cpu) { long opens = 0, ebusy = 0, other = 0; pin_cpu(cpu); while (access(STOPF, F_OK) != 0) { int fd = open(dev, O_RDONLY); if (fd >= 0) { opens++; close(fd); } else if (errno == EBUSY) { ebusy++; } else { other++; } } printf("[hammer %s cpu%d] opens=%ld ebusy=%ld other=%ld\n", dev, cpu, opens, ebusy, other); _exit(0); } int main(int argc, char **argv) { double secs = 10.0, t0; pid_t pa, pb; int st; if (argc > 1) secs = atof(argv[1]); setvbuf(stdout, NULL, _IOLBF, 0); unlink(STOPF); printf("[*] DF-5436 racer: free-running pinned processes, %.1f s\n", secs); printf("[*] baseline kernel counters: opens_while_open=%d " "double_simul=%d polls=%d resets=%d a=%d b=%d ebusy=%d\n", sysctl_int("hw.hx5436.opens_while_open"), sysctl_int("hw.hx5436.double_open_simul"), sysctl_int("hw.hx5436.polls_while_open"), sysctl_int("hw.hx5436.resets_while_open"), sysctl_int("hw.hx5436.a_opens"), sysctl_int("hw.hx5436.b_opens"), sysctl_int("hw.hx5436.ebusy")); pb = fork(); if (pb == 0) hammer(DEVB, 1); /* /dev/unlpt0 role */ pa = fork(); if (pa == 0) hammer(DEVA, 0); /* /dev/ulpt0 role */ t0 = now_sec(); while (now_sec() - t0 < secs) usleep(100000); close(open(STOPF, O_CREAT | O_WRONLY, 0644)); waitpid(pa, &st, 0); waitpid(pb, &st, 0); unlink(STOPF); printf("[R] kernel: opens_while_open=%d double_simul=%d " "polls_while_open=%d resets_while_open=%d a=%d b=%d ebusy=%d\n", sysctl_int("hw.hx5436.opens_while_open"), sysctl_int("hw.hx5436.double_open_simul"), sysctl_int("hw.hx5436.polls_while_open"), sysctl_int("hw.hx5436.resets_while_open"), sysctl_int("hw.hx5436.a_opens"), sysctl_int("hw.hx5436.b_opens"), sysctl_int("hw.hx5436.ebusy")); return (0); } |