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