xref: /freebsd/tools/test/stress2/misc/kevent9.sh (revision 2dd83b3f0507fc7bc64b908fb88f285a3b9663c8)
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