1 /* $NetBSD: cyclic_test.c,v 1.3 2018/05/28 21:05:02 chs Exp $ */
2
3 /*-
4 * Copyright 2007 John Birrell <jb@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: head/sys/cddl/dev/cyclic/cyclic_test.c 179260 2008-05-23 22:21:58Z jb $
28 *
29 */
30
31 #include <sys/cdefs.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/conf.h>
35 #include <sys/kthread.h>
36 #include <sys/module.h>
37 #include <sys/sysctl.h>
38 #include <sys/cyclic.h>
39 #include <sys/time.h>
40
41 static struct timespec test_001_start;
42
43 static void
cyclic_test_001_func(void * arg)44 cyclic_test_001_func(void *arg)
45 {
46 struct timespec ts;
47
48 nanotime(&ts);
49 timespecsub(&ts,&test_001_start);
50 printf("%s: called after %lu.%09lu on curcpu %d\n",__func__,(u_long) ts.tv_sec,(u_long) ts.tv_nsec, curcpu);
51 }
52
53 static void
cyclic_test_001(void)54 cyclic_test_001(void)
55 {
56 int error = 0;
57 cyc_handler_t hdlr;
58 cyc_time_t when;
59 cyclic_id_t id;
60
61 printf("%s: starting\n",__func__);
62
63 hdlr.cyh_func = (cyc_func_t) cyclic_test_001_func;
64 hdlr.cyh_arg = 0;
65
66 when.cyt_when = 0;
67 when.cyt_interval = 1000000000;
68
69 nanotime(&test_001_start);
70
71 mutex_enter(&cpu_lock);
72
73 id = cyclic_add(&hdlr, &when);
74
75 mutex_exit(&cpu_lock);
76
77 DELAY(1200000);
78
79 mutex_enter(&cpu_lock);
80
81 cyclic_remove(id);
82
83 mutex_exit(&cpu_lock);
84
85 printf("%s: %s\n",__func__, error == 0 ? "passed":"failed");
86 }
87
88 static struct timespec test_002_start;
89
90 static void
cyclic_test_002_func(void * arg)91 cyclic_test_002_func(void *arg)
92 {
93 struct timespec ts;
94
95 nanotime(&ts);
96 timespecsub(&ts,&test_002_start);
97 printf("%s: called after %lu.%09lu on curcpu %d\n",__func__,(u_long) ts.tv_sec,(u_long) ts.tv_nsec, curcpu);
98 }
99
100 static void
cyclic_test_002_online(void * arg,cpu_t * c,cyc_handler_t * hdlr,cyc_time_t * t)101 cyclic_test_002_online(void *arg, cpu_t *c, cyc_handler_t *hdlr, cyc_time_t *t)
102 {
103 printf("%s: online on curcpu %d\n",__func__, curcpu);
104 hdlr->cyh_func = cyclic_test_002_func;
105 hdlr->cyh_arg = NULL;
106 t->cyt_when = 0;
107 t->cyt_interval = 1000000000;
108 }
109
110 static void
cyclic_test_002_offline(void * arg,cpu_t * c,void * arg1)111 cyclic_test_002_offline(void *arg, cpu_t *c, void *arg1)
112 {
113 printf("%s: offline on curcpu %d\n",__func__, curcpu);
114 }
115
116 static void
cyclic_test_002(void)117 cyclic_test_002(void)
118 {
119 int error = 0;
120 cyc_omni_handler_t hdlr;
121 cyclic_id_t id;
122
123 printf("%s: starting\n",__func__);
124
125 hdlr.cyo_online = cyclic_test_002_online;
126 hdlr.cyo_offline = cyclic_test_002_offline;
127 hdlr.cyo_arg = NULL;
128
129 nanotime(&test_002_start);
130
131 mutex_enter(&cpu_lock);
132
133 id = cyclic_add_omni(&hdlr);
134
135 mutex_exit(&cpu_lock);
136
137 DELAY(1200000);
138
139 mutex_enter(&cpu_lock);
140
141 cyclic_remove(id);
142
143 mutex_exit(&cpu_lock);
144
145 printf("%s: %s\n",__func__, error == 0 ? "passed":"failed");
146 }
147
148 static struct timespec test_003_start;
149
150 static void
cyclic_test_003_func(void * arg)151 cyclic_test_003_func(void *arg)
152 {
153 struct timespec ts;
154
155 nanotime(&ts);
156 timespecsub(&ts,&test_003_start);
157 printf("%s: called after %lu.%09lu on curcpu %d id %ju\n",__func__,(u_long) ts.tv_sec,(u_long) ts.tv_nsec, curcpu, (uintmax_t)(uintptr_t) arg);
158 }
159
160 static void
cyclic_test_003(void)161 cyclic_test_003(void)
162 {
163 int error = 0;
164 cyc_handler_t hdlr;
165 cyc_time_t when;
166 cyclic_id_t id;
167 cyclic_id_t id1;
168 cyclic_id_t id2;
169 cyclic_id_t id3;
170
171 printf("%s: starting\n",__func__);
172
173 hdlr.cyh_func = (cyc_func_t) cyclic_test_003_func;
174
175 when.cyt_when = 0;
176
177 nanotime(&test_003_start);
178
179 mutex_enter(&cpu_lock);
180
181 when.cyt_interval = 200000000;
182 hdlr.cyh_arg = (void *) 0UL;
183 id = cyclic_add(&hdlr, &when);
184
185 when.cyt_interval = 400000000;
186 hdlr.cyh_arg = (void *) 1UL;
187 id1 = cyclic_add(&hdlr, &when);
188
189 hdlr.cyh_arg = (void *) 2UL;
190 when.cyt_interval = 1000000000;
191 id2 = cyclic_add(&hdlr, &when);
192
193 hdlr.cyh_arg = (void *) 3UL;
194 when.cyt_interval = 1300000000;
195 id3 = cyclic_add(&hdlr, &when);
196
197 mutex_exit(&cpu_lock);
198
199 DELAY(1200000);
200
201 mutex_enter(&cpu_lock);
202
203 cyclic_remove(id);
204 cyclic_remove(id1);
205 cyclic_remove(id2);
206 cyclic_remove(id3);
207
208 mutex_exit(&cpu_lock);
209
210 printf("%s: %s\n",__func__, error == 0 ? "passed":"failed");
211 }
212
213 /* Kernel thread command routine. */
214 static void
cyclic_run_tests(void * arg)215 cyclic_run_tests(void *arg)
216 {
217 intptr_t cmd = (intptr_t) arg;
218
219 switch (cmd) {
220 case 1:
221 cyclic_test_001();
222 break;
223 case 2:
224 cyclic_test_002();
225 break;
226 case 3:
227 cyclic_test_003();
228 break;
229 default:
230 cyclic_test_001();
231 cyclic_test_002();
232 cyclic_test_003();
233 break;
234 }
235
236 printf("%s: finished\n",__func__);
237
238 kthread_exit();
239 }
240
241 static int
cyclic_test(SYSCTL_HANDLER_ARGS)242 cyclic_test(SYSCTL_HANDLER_ARGS)
243 {
244 int error, cmd = 0;
245
246 error = sysctl_wire_old_buffer(req, sizeof(int));
247 if (error == 0)
248 error = sysctl_handle_int(oidp, &cmd, 0, req);
249 if (error != 0 || req->newptr == NULL)
250 return (error);
251
252 /* Check for command validity. */
253 switch (cmd) {
254 case 1:
255 case 2:
256 case -1:
257 /*
258 * Execute the tests in a kernel thread to avoid blocking
259 * the sysctl. Look for the results in the syslog.
260 */
261 error = kthread_add(cyclic_run_tests, (void *)(uintptr_t) cmd,
262 NULL, NULL, 0, 0, "cyctest%d", cmd);
263 break;
264 default:
265 printf("Usage: debug.cyclic.test=(1..9) or -1 for all tests\n");
266 error = EINVAL;
267 break;
268 }
269
270 return (error);
271 }
272
273 SYSCTL_NODE(_debug, OID_AUTO, cyclic, CTLFLAG_RW, NULL, "Cyclic nodes");
274 SYSCTL_PROC(_debug_cyclic, OID_AUTO, test, CTLTYPE_INT | CTLFLAG_RW, 0, 0,
275 cyclic_test, "I", "Enables a cyclic test. Use -1 for all tests.");
276
277 static int
cyclic_test_modevent(module_t mod,int type,void * data)278 cyclic_test_modevent(module_t mod, int type, void *data)
279 {
280 int error = 0;
281
282 switch (type) {
283 case MOD_LOAD:
284 break;
285
286 case MOD_UNLOAD:
287 break;
288
289 case MOD_SHUTDOWN:
290 break;
291
292 default:
293 error = EOPNOTSUPP;
294 break;
295
296 }
297 return (error);
298 }
299
300 DEV_MODULE(cyclic_test, cyclic_test_modevent, NULL);
301 MODULE_VERSION(cyclic_test, 1);
302 MODULE_DEPEND(cyclic_test, cyclic, 1, 1, 1);
303 MODULE_DEPEND(cyclic_test, opensolaris, 1, 1, 1);
304