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