2 * Copyright (c) 2015 Netflix, Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 #include <sys/cdefs.h>
26 __FBSDID("$FreeBSD$");
28 #include <sys/param.h>
29 #include <sys/systm.h>
31 #include <sys/cpuctl.h>
32 #include <sys/fcntl.h>
33 #include <sys/ioccom.h>
34 #include <sys/kernel.h>
35 #include <sys/libkern.h>
36 #include <sys/malloc.h>
37 #include <sys/module.h>
38 #include <sys/mutex.h>
40 #include <sys/pmckern.h>
43 #include <sys/queue.h>
44 #include <sys/sched.h>
46 #include <sys/sysctl.h>
48 #include <tests/kern_testfrwk.h>
49 #include <tests/callout_test.h>
50 #include <machine/cpu.h>
52 MALLOC_DEFINE(M_CALLTMP, "Temp callout Memory", "CalloutTest");
56 struct callout *co_array;
58 int co_number_callouts;
68 static struct callout_run *comaster[MAXCPU];
70 uint64_t callout_total = 0;
72 static void execute_the_co_test(struct callout_run *rn);
77 struct callout_run *rn;
79 rn = (struct callout_run *)arg;
80 printf("The callout test is now complete for thread %d\n",
82 printf("number_callouts:%d\n",
83 rn->co_number_callouts);
84 printf("Callouts that bailed (Not PENDING or ACTIVE cleared):%d\n",
86 printf("Callouts that completed:%d\n", rn->co_completed);
87 printf("Drain calls:%d\n", rn->drain_calls);
88 printf("Zero returns:%d non-zero:%d\n",
97 struct callout_run *rn;
99 rn = (struct callout_run *)arg;
102 mtx_unlock(&rn->lock);
106 test_callout(void *arg)
108 struct callout_run *rn;
114 rn = (struct callout_run *)arg;
115 atomic_add_int(&rn->callout_waiting, 1);
117 if (callout_pending(&rn->co_array[cpu]) ||
118 !callout_active(&rn->co_array[cpu])) {
120 atomic_subtract_int(&rn->callout_waiting, 1);
121 mtx_unlock(&rn->lock);
124 callout_deactivate(&rn->co_array[cpu]);
126 mtx_unlock(&rn->lock);
127 atomic_subtract_int(&rn->callout_waiting, 1);
131 execute_the_co_test(struct callout_run *rn)
134 uint32_t tk_s, tk_e, tk_d;
137 rn->callout_waiting = 0;
138 for (i = 0; i < rn->co_number_callouts; i++) {
139 if (rn->co_test == 1) {
140 /* start all on spread out cpu's */
142 callout_reset_sbt_on(&rn->co_array[i], 3, 0, test_callout, rn,
145 /* Start all on the same CPU */
146 callout_reset_sbt_on(&rn->co_array[i], 3, 0, test_callout, rn,
151 while (rn->callout_waiting != rn->co_number_callouts) {
159 /* OK everyone is waiting and we have the lock */
160 for (i = 0; i < rn->co_number_callouts; i++) {
161 ret = callout_async_drain(&rn->co_array[i], drainit);
168 rn->callout_waiting -= rn->cnt_one;
169 mtx_unlock(&rn->lock);
170 /* Now wait until all are done */
172 while (rn->callout_waiting > 0) {
180 co_saydone((void *)rn);
185 run_callout_test(struct kern_test *test)
187 struct callout_test *u;
190 struct callout_run *rn;
191 int index = test->tot_threads_running;
193 u = (struct callout_test *)test->test_options;
194 if (comaster[index] == NULL) {
195 rn = comaster[index] = malloc(sizeof(struct callout_run), M_CALLTMP, M_WAITOK);
196 memset(comaster[index], 0, sizeof(struct callout_run));
197 mtx_init(&rn->lock, "callouttest", NULL, MTX_DUPOK);
200 rn = comaster[index];
201 rn->co_number_callouts = rn->co_return_npa = 0;
202 rn->co_completed = rn->callout_waiting = 0;
203 rn->drain_calls = rn->cnt_zero = rn->cnt_one = 0;
205 free(rn->co_array, M_CALLTMP);
209 rn->co_number_callouts = u->number_of_callouts;
210 rn->co_test = u->test_number;
211 sz = sizeof(struct callout) * rn->co_number_callouts;
212 rn->co_array = malloc(sz, M_CALLTMP, M_WAITOK);
213 for (i = 0; i < rn->co_number_callouts; i++) {
214 callout_init(&rn->co_array[i], CALLOUT_MPSAFE);
216 execute_the_co_test(rn);
219 int callout_test_is_loaded = 0;
226 for (i = 0; i < MAXCPU; i++) {
228 if (comaster[i]->co_array) {
229 free(comaster[i]->co_array, M_CALLTMP);
230 comaster[i]->co_array = NULL;
232 free(comaster[i], M_CALLTMP);
239 callout_test_modevent(module_t mod, int type, void *data)
245 err = kern_testframework_register("callout_test",
248 printf("Can't load callout_test err:%d returned\n",
251 memset(comaster, 0, sizeof(comaster));
252 callout_test_is_loaded = 1;
256 err = kern_testframework_deregister("callout_test");
258 callout_test_is_loaded = 0;
263 if (callout_test_is_loaded) {
264 err = kern_testframework_deregister("callout_test");
267 callout_test_is_loaded = 0;
277 static moduledata_t callout_test_mod = {
278 .name = "callout_test",
279 .evhand = callout_test_modevent,
283 MODULE_DEPEND(callout_test, kern_testframework, 1, 1, 1);
284 DECLARE_MODULE(callout_test, callout_test_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);