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 39static struct timespec test_001_start; 40 41static void 42cyclic_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 51static void 52cyclic_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 86static struct timespec test_002_start; 87 88static void 89cyclic_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 98static void 99cyclic_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 108static void 109cyclic_test_002_offline(void *arg, cpu_t *c, void *arg1) 110{ 111 printf("%s: offline on curcpu %d\n",__func__, curcpu); 112} 113 114static void 115cyclic_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 146static struct timespec test_003_start; 147 148static void 149cyclic_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 158static void 159cyclic_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. */ 212static void 213cyclic_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 239static int 240cyclic_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 271SYSCTL_NODE(_debug, OID_AUTO, cyclic, CTLFLAG_RW, NULL, "Cyclic nodes"); 272SYSCTL_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 275static int 276cyclic_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 298DEV_MODULE(cyclic_test, cyclic_test_modevent, NULL); 299MODULE_VERSION(cyclic_test, 1); 300MODULE_DEPEND(cyclic_test, cyclic, 1, 1, 1); 301MODULE_DEPEND(cyclic_test, opensolaris, 1, 1, 1); 302