1/*	$NetBSD: cyclic_test.c,v 1.2 2010/02/21 01:46:33 darran 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: src/sys/cddl/dev/cyclic/cyclic_test.c,v 1.1.4.1 2009/08/03 08:13:06 kensmith Exp $
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
41static struct timespec test_001_start;
42
43static void
44cyclic_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
53static void
54cyclic_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
88static struct timespec test_002_start;
89
90static void
91cyclic_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
100static void
101cyclic_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
110static void
111cyclic_test_002_offline(void *arg, cpu_t *c, void *arg1)
112{
113	printf("%s: offline on curcpu %d\n",__func__, curcpu);
114}
115
116static void
117cyclic_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
148static struct timespec test_003_start;
149
150static void
151cyclic_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
160static void
161cyclic_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. */
214static void
215cyclic_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
241static int
242cyclic_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
273SYSCTL_NODE(_debug, OID_AUTO, cyclic, CTLFLAG_RW, NULL, "Cyclic nodes");
274SYSCTL_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
277static int
278cyclic_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
300DEV_MODULE(cyclic_test, cyclic_test_modevent, NULL);
301MODULE_VERSION(cyclic_test, 1);
302MODULE_DEPEND(cyclic_test, cyclic, 1, 1, 1);
303MODULE_DEPEND(cyclic_test, opensolaris, 1, 1, 1);
304