1 1.3 thorpej /* $NetBSD: threadpool_tester.c,v 1.3 2018/12/26 22:21:10 thorpej Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /*- 4 1.1 thorpej * Copyright (c) 2018 The NetBSD Foundation, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * This code is derived from software contributed to The NetBSD Foundation 8 1.1 thorpej * by Jason R. Thorpe. 9 1.1 thorpej * 10 1.1 thorpej * Redistribution and use in source and binary forms, with or without 11 1.1 thorpej * modification, are permitted provided that the following conditions 12 1.1 thorpej * are met: 13 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 14 1.1 thorpej * notice, this list of conditions and the following disclaimer. 15 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 17 1.1 thorpej * documentation and/or other materials provided with the distribution. 18 1.1 thorpej * 19 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE. 30 1.1 thorpej */ 31 1.1 thorpej 32 1.1 thorpej #include <sys/cdefs.h> 33 1.3 thorpej __KERNEL_RCSID(0, "$NetBSD: threadpool_tester.c,v 1.3 2018/12/26 22:21:10 thorpej Exp $"); 34 1.1 thorpej 35 1.1 thorpej #include <sys/param.h> 36 1.1 thorpej #include <sys/kernel.h> 37 1.1 thorpej #include <sys/module.h> 38 1.1 thorpej #include <sys/sysctl.h> 39 1.1 thorpej #include <sys/threadpool.h> 40 1.1 thorpej 41 1.1 thorpej MODULE(MODULE_CLASS_MISC, threadpool_tester, NULL); 42 1.1 thorpej 43 1.1 thorpej #ifdef THREADPOOL_VERBOSE 44 1.1 thorpej #define TP_LOG(x) printf x 45 1.1 thorpej #else 46 1.1 thorpej #define TP_LOG(x) /* nothing */ 47 1.1 thorpej #endif /* THREADPOOL_VERBOSE */ 48 1.1 thorpej 49 1.1 thorpej static struct tester_context { 50 1.1 thorpej kmutex_t ctx_mutex; 51 1.1 thorpej struct sysctllog *ctx_sysctllog; 52 1.2 thorpej struct threadpool *ctx_unbound[PRI_COUNT + 1]; 53 1.2 thorpej struct threadpool_percpu *ctx_percpu[PRI_COUNT + 1]; 54 1.1 thorpej unsigned int ctx_value; 55 1.2 thorpej struct threadpool_job ctx_job; 56 1.1 thorpej } tester_ctx; 57 1.1 thorpej 58 1.1 thorpej #define pri_to_idx(pri) ((pri) == PRI_NONE ? PRI_COUNT : (pri)) 59 1.1 thorpej 60 1.1 thorpej static bool 61 1.1 thorpej pri_is_valid(pri_t pri) 62 1.1 thorpej { 63 1.1 thorpej return (pri == PRI_NONE || (pri >= PRI_USER && pri < PRI_COUNT)); 64 1.1 thorpej } 65 1.1 thorpej 66 1.1 thorpej static int 67 1.1 thorpej threadpool_tester_get_unbound(SYSCTLFN_ARGS) 68 1.1 thorpej { 69 1.1 thorpej struct tester_context *ctx; 70 1.2 thorpej struct threadpool *pool, *opool = NULL; 71 1.1 thorpej struct sysctlnode node; 72 1.1 thorpej int error, val; 73 1.1 thorpej 74 1.1 thorpej node = *rnode; 75 1.1 thorpej ctx = node.sysctl_data; 76 1.1 thorpej 77 1.1 thorpej val = -1; 78 1.1 thorpej node.sysctl_data = &val; 79 1.1 thorpej error = sysctl_lookup(SYSCTLFN_CALL(&node)); 80 1.1 thorpej if (error || newp == NULL) 81 1.1 thorpej return error; 82 1.3 thorpej 83 1.1 thorpej if (! pri_is_valid(val)) 84 1.1 thorpej return EINVAL; 85 1.3 thorpej 86 1.1 thorpej error = threadpool_get(&pool, val); 87 1.1 thorpej if (error) { 88 1.1 thorpej TP_LOG(("%s: threadpool_get(..., %d) failed -> %d\n", 89 1.1 thorpej __func__, val, error)); 90 1.1 thorpej return error; 91 1.1 thorpej } 92 1.3 thorpej 93 1.1 thorpej mutex_enter(&ctx->ctx_mutex); 94 1.1 thorpej if (ctx->ctx_unbound[pri_to_idx(val)] == NULL) 95 1.1 thorpej ctx->ctx_unbound[pri_to_idx(val)] = pool; 96 1.1 thorpej else 97 1.1 thorpej opool = ctx->ctx_unbound[pri_to_idx(val)]; 98 1.1 thorpej mutex_exit(&ctx->ctx_mutex); 99 1.1 thorpej 100 1.1 thorpej if (opool != NULL) { 101 1.1 thorpej /* Should have gotten reference to existing pool. */ 102 1.1 thorpej TP_LOG(("%s: found existing unbound pool for pri %d (%s)\n", 103 1.1 thorpej __func__, val, opool == pool ? "match" : "NO MATCH")); 104 1.1 thorpej KASSERT(opool == pool); 105 1.1 thorpej threadpool_put(pool, val); 106 1.1 thorpej error = EEXIST; 107 1.1 thorpej } else { 108 1.1 thorpej TP_LOG(("%s: created unbound pool for pri %d\n", 109 1.1 thorpej __func__, val)); 110 1.1 thorpej } 111 1.1 thorpej 112 1.1 thorpej return error; 113 1.1 thorpej } 114 1.1 thorpej 115 1.1 thorpej static int 116 1.1 thorpej threadpool_tester_put_unbound(SYSCTLFN_ARGS) 117 1.1 thorpej { 118 1.1 thorpej struct tester_context *ctx; 119 1.2 thorpej struct threadpool *pool; 120 1.1 thorpej struct sysctlnode node; 121 1.1 thorpej int error, val; 122 1.1 thorpej 123 1.1 thorpej node = *rnode; 124 1.1 thorpej ctx = node.sysctl_data; 125 1.1 thorpej 126 1.1 thorpej val = -1; 127 1.1 thorpej node.sysctl_data = &val; 128 1.1 thorpej error = sysctl_lookup(SYSCTLFN_CALL(&node)); 129 1.1 thorpej if (error || newp == NULL) 130 1.1 thorpej return error; 131 1.3 thorpej 132 1.1 thorpej if (! pri_is_valid(val)) 133 1.1 thorpej return EINVAL; 134 1.3 thorpej 135 1.1 thorpej mutex_enter(&ctx->ctx_mutex); 136 1.1 thorpej /* We only ever maintain a single reference. */ 137 1.1 thorpej pool = ctx->ctx_unbound[pri_to_idx(val)]; 138 1.1 thorpej ctx->ctx_unbound[pri_to_idx(val)] = NULL; 139 1.1 thorpej mutex_exit(&ctx->ctx_mutex); 140 1.1 thorpej 141 1.1 thorpej if (pool == NULL) { 142 1.1 thorpej TP_LOG(("%s: no unbound pool for pri %d\n", 143 1.1 thorpej __func__, val)); 144 1.1 thorpej return ENODEV; 145 1.1 thorpej } 146 1.1 thorpej 147 1.1 thorpej threadpool_put(pool, val); 148 1.1 thorpej TP_LOG(("%s: released unbound pool for pri %d\n", 149 1.1 thorpej __func__, val)); 150 1.1 thorpej 151 1.1 thorpej return 0; 152 1.1 thorpej } 153 1.1 thorpej 154 1.1 thorpej static int 155 1.1 thorpej threadpool_tester_run_unbound(SYSCTLFN_ARGS) 156 1.1 thorpej { 157 1.1 thorpej struct tester_context *ctx; 158 1.2 thorpej struct threadpool *pool; 159 1.1 thorpej struct sysctlnode node; 160 1.1 thorpej int error, val; 161 1.1 thorpej 162 1.1 thorpej node = *rnode; 163 1.1 thorpej ctx = node.sysctl_data; 164 1.1 thorpej 165 1.1 thorpej val = -1; 166 1.1 thorpej node.sysctl_data = &val; 167 1.1 thorpej error = sysctl_lookup(SYSCTLFN_CALL(&node)); 168 1.1 thorpej if (error || newp == NULL) 169 1.1 thorpej return error; 170 1.3 thorpej 171 1.1 thorpej if (! pri_is_valid(val)) 172 1.1 thorpej return EINVAL; 173 1.1 thorpej 174 1.1 thorpej mutex_enter(&ctx->ctx_mutex); 175 1.1 thorpej pool = ctx->ctx_unbound[pri_to_idx(val)]; 176 1.1 thorpej if (pool == NULL) { 177 1.1 thorpej TP_LOG(("%s: no unbound pool for pri %d\n", 178 1.1 thorpej __func__, val)); 179 1.1 thorpej mutex_exit(&ctx->ctx_mutex); 180 1.1 thorpej return ENODEV; 181 1.1 thorpej } 182 1.1 thorpej 183 1.1 thorpej threadpool_schedule_job(pool, &ctx->ctx_job); 184 1.1 thorpej TP_LOG(("%s: scheduled job on unbound pool for pri %d\n", 185 1.1 thorpej __func__, val)); 186 1.1 thorpej mutex_exit(&ctx->ctx_mutex); 187 1.1 thorpej 188 1.1 thorpej return 0; 189 1.1 thorpej } 190 1.1 thorpej 191 1.1 thorpej static int 192 1.1 thorpej threadpool_tester_get_percpu(SYSCTLFN_ARGS) 193 1.1 thorpej { 194 1.1 thorpej struct tester_context *ctx; 195 1.2 thorpej struct threadpool_percpu *pcpu, *opcpu = NULL; 196 1.1 thorpej struct sysctlnode node; 197 1.1 thorpej int error, val; 198 1.1 thorpej 199 1.1 thorpej node = *rnode; 200 1.1 thorpej ctx = node.sysctl_data; 201 1.1 thorpej 202 1.1 thorpej val = -1; 203 1.1 thorpej node.sysctl_data = &val; 204 1.1 thorpej error = sysctl_lookup(SYSCTLFN_CALL(&node)); 205 1.1 thorpej if (error || newp == NULL) 206 1.1 thorpej return error; 207 1.3 thorpej 208 1.1 thorpej if (! pri_is_valid(val)) 209 1.1 thorpej return EINVAL; 210 1.3 thorpej 211 1.1 thorpej error = threadpool_percpu_get(&pcpu, val); 212 1.1 thorpej if (error) { 213 1.1 thorpej TP_LOG(("%s: threadpool_percpu_get(..., %d) failed -> %d\n", 214 1.1 thorpej __func__, val, error)); 215 1.1 thorpej return error; 216 1.1 thorpej } 217 1.3 thorpej 218 1.1 thorpej mutex_enter(&ctx->ctx_mutex); 219 1.1 thorpej if (ctx->ctx_percpu[pri_to_idx(val)] == NULL) 220 1.1 thorpej ctx->ctx_percpu[pri_to_idx(val)] = pcpu; 221 1.1 thorpej else 222 1.1 thorpej opcpu = ctx->ctx_percpu[pri_to_idx(val)]; 223 1.1 thorpej mutex_exit(&ctx->ctx_mutex); 224 1.1 thorpej 225 1.1 thorpej if (opcpu != NULL) { 226 1.1 thorpej /* Should have gotten reference to existing pool. */ 227 1.1 thorpej TP_LOG(("%s: found existing unbound pool for pri %d (%s)\n", 228 1.1 thorpej __func__, val, opcpu == pcpu ? "match" : "NO MATCH")); 229 1.1 thorpej KASSERT(opcpu == pcpu); 230 1.1 thorpej threadpool_percpu_put(pcpu, val); 231 1.1 thorpej error = EEXIST; 232 1.1 thorpej } else { 233 1.1 thorpej TP_LOG(("%s: created percpu pool for pri %d\n", 234 1.1 thorpej __func__, val)); 235 1.1 thorpej } 236 1.1 thorpej 237 1.1 thorpej return error; 238 1.1 thorpej } 239 1.1 thorpej 240 1.1 thorpej static int 241 1.1 thorpej threadpool_tester_put_percpu(SYSCTLFN_ARGS) 242 1.1 thorpej { 243 1.1 thorpej struct tester_context *ctx; 244 1.2 thorpej struct threadpool_percpu *pcpu; 245 1.1 thorpej struct sysctlnode node; 246 1.1 thorpej int error, val; 247 1.1 thorpej 248 1.1 thorpej node = *rnode; 249 1.1 thorpej ctx = node.sysctl_data; 250 1.1 thorpej 251 1.1 thorpej val = -1; 252 1.1 thorpej node.sysctl_data = &val; 253 1.1 thorpej error = sysctl_lookup(SYSCTLFN_CALL(&node)); 254 1.1 thorpej if (error || newp == NULL) 255 1.1 thorpej return error; 256 1.3 thorpej 257 1.1 thorpej if (! pri_is_valid(val)) 258 1.1 thorpej return EINVAL; 259 1.3 thorpej 260 1.1 thorpej mutex_enter(&ctx->ctx_mutex); 261 1.1 thorpej /* We only ever maintain a single reference. */ 262 1.1 thorpej pcpu = ctx->ctx_percpu[pri_to_idx(val)]; 263 1.1 thorpej ctx->ctx_percpu[pri_to_idx(val)] = NULL; 264 1.1 thorpej mutex_exit(&ctx->ctx_mutex); 265 1.1 thorpej 266 1.1 thorpej if (pcpu == NULL) { 267 1.1 thorpej TP_LOG(("%s: no percpu pool for pri %d\n", 268 1.1 thorpej __func__, val)); 269 1.1 thorpej return ENODEV; 270 1.1 thorpej } 271 1.1 thorpej 272 1.1 thorpej threadpool_percpu_put(pcpu, val); 273 1.1 thorpej TP_LOG(("%s: released percpu pool for pri %d\n", 274 1.1 thorpej __func__, val)); 275 1.1 thorpej 276 1.1 thorpej return 0; 277 1.1 thorpej } 278 1.1 thorpej 279 1.1 thorpej static int 280 1.1 thorpej threadpool_tester_run_percpu(SYSCTLFN_ARGS) 281 1.1 thorpej { 282 1.1 thorpej struct tester_context *ctx; 283 1.2 thorpej struct threadpool_percpu *pcpu; 284 1.2 thorpej struct threadpool *pool; 285 1.1 thorpej struct sysctlnode node; 286 1.1 thorpej int error, val; 287 1.1 thorpej 288 1.1 thorpej node = *rnode; 289 1.1 thorpej ctx = node.sysctl_data; 290 1.1 thorpej 291 1.1 thorpej val = -1; 292 1.1 thorpej node.sysctl_data = &val; 293 1.1 thorpej error = sysctl_lookup(SYSCTLFN_CALL(&node)); 294 1.1 thorpej if (error || newp == NULL) 295 1.1 thorpej return error; 296 1.3 thorpej 297 1.1 thorpej if (! pri_is_valid(val)) 298 1.1 thorpej return EINVAL; 299 1.1 thorpej 300 1.1 thorpej mutex_enter(&ctx->ctx_mutex); 301 1.1 thorpej pcpu = ctx->ctx_percpu[pri_to_idx(val)]; 302 1.1 thorpej if (pcpu == NULL) { 303 1.1 thorpej TP_LOG(("%s: no percpu pool for pri %d\n", 304 1.1 thorpej __func__, val)); 305 1.1 thorpej mutex_exit(&ctx->ctx_mutex); 306 1.1 thorpej return ENODEV; 307 1.1 thorpej } 308 1.1 thorpej 309 1.1 thorpej pool = threadpool_percpu_ref(pcpu); 310 1.1 thorpej KASSERT(pool != NULL); 311 1.1 thorpej 312 1.1 thorpej threadpool_schedule_job(pool, &ctx->ctx_job); 313 1.1 thorpej TP_LOG(("%s: scheduled job on percpu pool for pri %d\n", 314 1.1 thorpej __func__, val)); 315 1.1 thorpej mutex_exit(&ctx->ctx_mutex); 316 1.1 thorpej 317 1.1 thorpej return 0; 318 1.1 thorpej } 319 1.1 thorpej 320 1.1 thorpej static int 321 1.1 thorpej threadpool_tester_test_value(SYSCTLFN_ARGS) 322 1.1 thorpej { 323 1.1 thorpej struct tester_context *ctx; 324 1.1 thorpej struct sysctlnode node; 325 1.1 thorpej unsigned int val; 326 1.1 thorpej int error; 327 1.1 thorpej 328 1.1 thorpej node = *rnode; 329 1.1 thorpej ctx = node.sysctl_data; 330 1.1 thorpej 331 1.1 thorpej mutex_enter(&ctx->ctx_mutex); 332 1.1 thorpej val = ctx->ctx_value; 333 1.1 thorpej node.sysctl_data = &val; 334 1.1 thorpej error = sysctl_lookup(SYSCTLFN_CALL(&node)); 335 1.1 thorpej if (error || newp == NULL) { 336 1.1 thorpej mutex_exit(&ctx->ctx_mutex); 337 1.1 thorpej return error; 338 1.1 thorpej } 339 1.1 thorpej ctx->ctx_value = val; 340 1.1 thorpej mutex_exit(&ctx->ctx_mutex); 341 1.1 thorpej 342 1.1 thorpej return 0; 343 1.1 thorpej } 344 1.1 thorpej 345 1.1 thorpej static void 346 1.2 thorpej threadpool_tester_job(struct threadpool_job *job) 347 1.1 thorpej { 348 1.1 thorpej struct tester_context *ctx = 349 1.1 thorpej container_of(job, struct tester_context, ctx_job); 350 1.1 thorpej unsigned int oval, nval; 351 1.1 thorpej 352 1.1 thorpej TP_LOG(("%s: job = %p, ctx = %p\n", __func__, job, ctx)); 353 1.1 thorpej 354 1.1 thorpej mutex_enter(&ctx->ctx_mutex); 355 1.1 thorpej oval = ctx->ctx_value; 356 1.1 thorpej nval = oval + 1; /* always reference oval and nval */ 357 1.1 thorpej ctx->ctx_value = nval; 358 1.1 thorpej mutex_exit(&ctx->ctx_mutex); 359 1.1 thorpej 360 1.1 thorpej TP_LOG(("%s: %u -> %u\n", __func__, oval, nval)); 361 1.1 thorpej (void) kpause("tptestjob", false, hz, NULL); 362 1.1 thorpej 363 1.1 thorpej mutex_enter(&ctx->ctx_mutex); 364 1.1 thorpej threadpool_job_done(job); 365 1.1 thorpej mutex_exit(&ctx->ctx_mutex); 366 1.1 thorpej } 367 1.1 thorpej 368 1.1 thorpej #define RETURN_ERROR if (error) goto return_error 369 1.1 thorpej 370 1.1 thorpej static int 371 1.1 thorpej threadpool_tester_init(void) 372 1.1 thorpej { 373 1.1 thorpej struct sysctllog **log = &tester_ctx.ctx_sysctllog; 374 1.1 thorpej const struct sysctlnode *rnode, *cnode; 375 1.1 thorpej int error; 376 1.1 thorpej 377 1.1 thorpej mutex_init(&tester_ctx.ctx_mutex, MUTEX_DEFAULT, IPL_NONE); 378 1.1 thorpej threadpool_job_init(&tester_ctx.ctx_job, threadpool_tester_job, 379 1.1 thorpej &tester_ctx.ctx_mutex, "tptest"); 380 1.1 thorpej 381 1.1 thorpej error = sysctl_createv(log, 0, NULL, &rnode, CTLFLAG_PERMANENT, 382 1.1 thorpej CTLTYPE_NODE, "threadpool_tester", 383 1.1 thorpej SYSCTL_DESCR("threadpool testing interface"), 384 1.1 thorpej NULL, 0, NULL, 0, CTL_KERN, CTL_CREATE, CTL_EOL); 385 1.1 thorpej RETURN_ERROR; 386 1.1 thorpej 387 1.1 thorpej error = sysctl_createv(log, 0, &rnode, &cnode, 388 1.1 thorpej CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "get_unbound", 389 1.1 thorpej SYSCTL_DESCR("get unbound pool of specified priority"), 390 1.1 thorpej threadpool_tester_get_unbound, 0, 391 1.1 thorpej (void *)&tester_ctx, 0, CTL_CREATE, CTL_EOL); 392 1.1 thorpej RETURN_ERROR; 393 1.1 thorpej 394 1.1 thorpej error = sysctl_createv(log, 0, &rnode, &cnode, 395 1.1 thorpej CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "put_unbound", 396 1.1 thorpej SYSCTL_DESCR("put unbound pool of specified priority"), 397 1.1 thorpej threadpool_tester_put_unbound, 0, 398 1.1 thorpej (void *)&tester_ctx, 0, CTL_CREATE, CTL_EOL); 399 1.1 thorpej RETURN_ERROR; 400 1.1 thorpej 401 1.1 thorpej error = sysctl_createv(log, 0, &rnode, &cnode, 402 1.1 thorpej CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "run_unbound", 403 1.1 thorpej SYSCTL_DESCR("run on unbound pool of specified priority"), 404 1.1 thorpej threadpool_tester_run_unbound, 0, 405 1.1 thorpej (void *)&tester_ctx, 0, CTL_CREATE, CTL_EOL); 406 1.1 thorpej RETURN_ERROR; 407 1.1 thorpej 408 1.1 thorpej error = sysctl_createv(log, 0, &rnode, &cnode, 409 1.1 thorpej CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "get_percpu", 410 1.1 thorpej SYSCTL_DESCR("get percpu pool of specified priority"), 411 1.1 thorpej threadpool_tester_get_percpu, 0, 412 1.1 thorpej (void *)&tester_ctx, 0, CTL_CREATE, CTL_EOL); 413 1.1 thorpej RETURN_ERROR; 414 1.1 thorpej 415 1.1 thorpej error = sysctl_createv(log, 0, &rnode, &cnode, 416 1.1 thorpej CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "put_percpu", 417 1.1 thorpej SYSCTL_DESCR("put percpu pool of specified priority"), 418 1.1 thorpej threadpool_tester_put_percpu, 0, 419 1.1 thorpej (void *)&tester_ctx, 0, CTL_CREATE, CTL_EOL); 420 1.1 thorpej RETURN_ERROR; 421 1.1 thorpej 422 1.1 thorpej error = sysctl_createv(log, 0, &rnode, &cnode, 423 1.1 thorpej CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "run_percpu", 424 1.1 thorpej SYSCTL_DESCR("run on percpu pool of specified priority"), 425 1.1 thorpej threadpool_tester_run_percpu, 0, 426 1.1 thorpej (void *)&tester_ctx, 0, CTL_CREATE, CTL_EOL); 427 1.1 thorpej RETURN_ERROR; 428 1.1 thorpej 429 1.1 thorpej error = sysctl_createv(log, 0, &rnode, &cnode, 430 1.1 thorpej CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "test_value", 431 1.1 thorpej SYSCTL_DESCR("test value that jobs increment"), 432 1.1 thorpej threadpool_tester_test_value, 0, 433 1.1 thorpej (void *)&tester_ctx, 0, CTL_CREATE, CTL_EOL); 434 1.1 thorpej RETURN_ERROR; 435 1.1 thorpej 436 1.1 thorpej return 0; 437 1.1 thorpej 438 1.1 thorpej return_error: 439 1.1 thorpej sysctl_teardown(log); 440 1.1 thorpej return error; 441 1.1 thorpej } 442 1.1 thorpej 443 1.1 thorpej static int 444 1.1 thorpej threadpool_tester_fini(void) 445 1.1 thorpej { 446 1.1 thorpej pri_t pri; 447 1.1 thorpej 448 1.1 thorpej mutex_enter(&tester_ctx.ctx_mutex); 449 1.1 thorpej for (pri = PRI_NONE/*-1*/; pri < PRI_COUNT; pri++) { 450 1.2 thorpej struct threadpool *pool = 451 1.1 thorpej tester_ctx.ctx_unbound[pri_to_idx(pri)]; 452 1.2 thorpej struct threadpool_percpu *pcpu = 453 1.1 thorpej tester_ctx.ctx_percpu[pri_to_idx(pri)]; 454 1.1 thorpej 455 1.1 thorpej /* 456 1.1 thorpej * threadpool_cancel_job() may be called on a pool 457 1.1 thorpej * other than what the job is scheduled on. This is 458 1.1 thorpej * safe; see comment in threadpool_cancel_job_async(). 459 1.1 thorpej */ 460 1.1 thorpej 461 1.1 thorpej if (pool != NULL) { 462 1.1 thorpej threadpool_cancel_job(pool, &tester_ctx.ctx_job); 463 1.1 thorpej threadpool_put(pool, pri); 464 1.1 thorpej tester_ctx.ctx_unbound[pri_to_idx(pri)] = NULL; 465 1.1 thorpej } 466 1.1 thorpej if (pcpu != NULL) { 467 1.1 thorpej pool = threadpool_percpu_ref(pcpu); 468 1.1 thorpej threadpool_cancel_job(pool, &tester_ctx.ctx_job); 469 1.1 thorpej threadpool_percpu_put(pcpu, pri); 470 1.1 thorpej tester_ctx.ctx_percpu[pri_to_idx(pri)] = NULL; 471 1.1 thorpej } 472 1.1 thorpej } 473 1.1 thorpej mutex_exit(&tester_ctx.ctx_mutex); 474 1.1 thorpej threadpool_job_destroy(&tester_ctx.ctx_job); 475 1.1 thorpej mutex_destroy(&tester_ctx.ctx_mutex); 476 1.1 thorpej 477 1.1 thorpej sysctl_teardown(&tester_ctx.ctx_sysctllog); 478 1.3 thorpej 479 1.1 thorpej return 0; 480 1.1 thorpej } 481 1.1 thorpej 482 1.1 thorpej static int 483 1.1 thorpej threadpool_tester_modcmd(modcmd_t cmd, void *arg __unused) 484 1.1 thorpej { 485 1.1 thorpej int error; 486 1.1 thorpej 487 1.1 thorpej switch (cmd) { 488 1.1 thorpej case MODULE_CMD_INIT: 489 1.1 thorpej error = threadpool_tester_init(); 490 1.1 thorpej break; 491 1.3 thorpej 492 1.1 thorpej case MODULE_CMD_FINI: 493 1.1 thorpej error = threadpool_tester_fini(); 494 1.1 thorpej break; 495 1.3 thorpej 496 1.1 thorpej case MODULE_CMD_STAT: 497 1.1 thorpej default: 498 1.1 thorpej error = ENOTTY; 499 1.1 thorpej } 500 1.1 thorpej 501 1.1 thorpej return error; 502 1.1 thorpej } 503