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