DF-0019 / load.c
/* * DF-0019 trigger — heavy workload to force bsd4_chooseproc_locked_cache_coherent * to run with a non-empty runqueue while queue_checks=0. * * Strategy: fork N children that do short sleeps + CPU spin. The sleeps force * them through acquire/release_curproc repeatedly while the runqueue is hot. * With queue_checks=0, the very first call to chooseproc_locked_cache_coherent * that finds ANY process on rt/ts/id queues will skip the while loop, * dereference min_level_lwp (NULL), and trip KASSERT at usched_bsd4.c:1548. */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <sys/wait.h> #include <sys/types.h> #include <errno.h> #include <string.h> #define NKIDS 40 static volatile sig_atomic_t stop = 0; static void handler(int s) { stop = 1; } int main(void) { int i; pid_t kids[NKIDS]; signal(SIGALRM, handler); fprintf(stderr, "[*] launcher: pid=%d, forking %d CPU-bound kids\n", (int)getpid(), NKIDS); for (i = 0; i < NKIDS; i++) { pid_t p = fork(); if (p == 0) { /* child: tight CPU spin with occasional yield */ alarm(20); while (!stop) { volatile unsigned long x = 0; for (volatile int j = 0; j < 100000; j++) x += j; /* short sleep to force acquire/release cycle */ usleep(100); } _exit(0); } kids[i] = p; } /* parent also spins */ alarm(15); while (!stop) { volatile unsigned long x = 0; for (volatile int j = 0; j < 1000000; j++) x += j; } fprintf(stderr, "[*] parent done spinning, reaping kids\n"); for (i = 0; i < NKIDS; i++) { kill(kids[i], SIGTERM); } for (i = 0; i < NKIDS; i++) { int st; waitpid(kids[i], &st, 0); } fprintf(stderr, "[*] survived — no panic (FIXED kernel or path not hit). exit 0.\n"); return 0; } |