1#!/bin/sh 2 3# Test scenario by Eric Badger <eric badgerio us> 4 5# userret: returning with the following locks held: 6# exclusive sleep mutex process lock (process lock) r = 0 (0xcb714758) 7# locked @ kern/kern_event.c:2125 8# panic: witness_warn 9 10# https://people.freebsd.org/~pho/stress/log/kevent9.txt 11# Fixed in r302235. 12 13. ../default.cfg 14 15[ `sysctl -n hw.ncpu` -ne 4 ] && echo "For best results use hw.ncpu == 4" 16 17cd /tmp 18cat > /tmp/kevent9-1.c <<EOF 19#include <sys/event.h> 20#include <sys/time.h> 21#include <sys/types.h> 22#include <sys/wait.h> 23#include <sys/wait.h> 24 25#include <err.h> 26#include <pthread.h> 27#include <pthread_np.h> 28#include <signal.h> 29#include <stdio.h> 30#include <stdlib.h> 31#include <string.h> 32#include <unistd.h> 33 34#define NUM_PROCS 4000 35 36void *procmaker(void *arg __unused) 37{ 38 pthread_set_name_np(pthread_self(), "procmaker"); 39 for (int i = 0; i < NUM_PROCS; ++i) 40 { 41 struct timespec ts; 42 ts.tv_sec = 0; 43 ts.tv_nsec = 50000; 44 nanosleep(&ts, NULL); 45 switch(fork()) 46 { 47 case -1: 48 err(1, "fork"); 49 break; 50 case 0: 51 execl("./kevent9-2", "kevent9-2", NULL); 52 _exit(127); 53 break; 54 default: 55 break; 56 } 57 } 58 printf("done forking\n"); 59 return NULL; 60} 61 62void *reaper(void *arg __unused) 63{ 64 pthread_set_name_np(pthread_self(), "reaper"); 65 int counter = 0; 66 while (counter < NUM_PROCS) 67 { 68 int status; 69 if (wait(&status) > 0) 70 { 71 ++counter; 72 } 73 } 74 printf("Reaped %d\n", counter); 75 return NULL; 76} 77 78int main() 79{ 80 pthread_set_name_np(pthread_self(), "main"); 81 82 int kqfd = kqueue(); 83 if (kqfd == -1) 84 { 85 err(1, "kqueue()"); 86 } 87 88 struct kevent change; 89 memset(&change, 0, sizeof(change)); 90 change.ident = getpid(); 91 change.filter = EVFILT_PROC; 92 change.flags = EV_ADD | EV_ENABLE; 93 change.fflags = NOTE_EXIT | NOTE_EXEC | NOTE_FORK | NOTE_TRACK; 94 95 if (kevent(kqfd, &change, 1, NULL, 0, NULL) == -1) 96 { 97 err(1, "kevent change"); 98 } 99 100 pthread_t t; 101 pthread_create(&t, NULL, procmaker, NULL); 102 pthread_create(&t, NULL, reaper, NULL); 103 104 int numexecs = 0; 105 int numexits = 0; 106 int numforks = 0; 107 int nummults = 0; 108 int numchlds = 0; 109 int numterrs = 0; 110 111 while (1) 112 { 113 struct kevent event; 114 struct timespec to; 115 to.tv_sec = 1; 116 to.tv_nsec = 0; 117 int ret = kevent(kqfd, NULL, 0, &event, 1, &to); 118 if (ret == -1) 119 { 120 err(1, "kevent event"); 121 } 122 else if (ret == 0) 123 { 124 printf("numexecs: %d numexits: %d numforks: %d numchlds: %d numterrs: %d nummults: %d\n", 125 numexecs, numexits, numforks, numchlds, numterrs, nummults); 126 127 // Sometimes we miss a NOTE_EXIT. If it hasn't arrived by the timeout, bail out since 128 // it will probably never arrive. 129 break; 130 /* 131 if (numexits == NUM_PROCS) 132 { 133 break; 134 } 135 else 136 { 137 continue; 138 } 139 */ 140 } 141 142 int numflags = 0; 143 if (event.fflags & NOTE_EXEC) 144 { 145 ++numflags; 146 ++numexecs; 147 } 148 if (event.fflags & NOTE_EXIT) 149 { 150 ++numflags; 151 ++numexits; 152 } 153 if (event.fflags & NOTE_FORK) 154 { 155 ++numflags; 156 ++numforks; 157 } 158 if (event.fflags & NOTE_CHILD) 159 { 160 ++numflags; 161 ++numchlds; 162 } 163 if (event.fflags & NOTE_TRACKERR) 164 { 165 ++numflags; 166 ++numterrs; 167 } 168 if (numflags > 1) 169 { 170 ++nummults; 171 } 172 173 /* 174 struct timespec ts; 175 ts.tv_sec = 0; 176 ts.tv_nsec = 50000; 177 nanosleep(&ts, NULL); 178 */ 179 } 180 return 0; 181} 182EOF 183 184cat > /tmp/kevent9-2.c <<EOF 185#include <time.h> 186 187int main() 188{ 189 struct timespec ts; 190 ts.tv_sec = 0; 191 ts.tv_nsec = 1000; 192 nanosleep(&ts, NULL); 193 return 0; 194} 195EOF 196 197mycc -o kevent9-1 -Wall -Wextra -O2 -g kevent9-1.c -lpthread || exit 1 198mycc -o kevent9-2 -Wall -Wextra -O2 -g kevent9-2.c || exit 1 199rm kevent9-1.c kevent9-2.c 200 201start=`date '+%s'` 202while [ $((`date '+%s'` - start)) -lt 300 ]; do 203 ./kevent9-1 > /dev/null 204done 205rm kevent9-1 kevent9-2 206exit 0 207