1*fd471022Sthorpej /* $NetBSD: threadpool.c,v 1.3 2018/12/26 18:54:20 thorpej Exp $ */ 277118773Sthorpej 377118773Sthorpej /*- 477118773Sthorpej * Copyright (c) 2018 The NetBSD Foundation, Inc. 577118773Sthorpej * All rights reserved. 677118773Sthorpej * 777118773Sthorpej * This code is derived from software contributed to The NetBSD Foundation 877118773Sthorpej * by Jason R. Thorpe. 977118773Sthorpej * 1077118773Sthorpej * Redistribution and use in source and binary forms, with or without 1177118773Sthorpej * modification, are permitted provided that the following conditions 1277118773Sthorpej * are met: 1377118773Sthorpej * 1. Redistributions of source code must retain the above copyright 1477118773Sthorpej * notice, this list of conditions and the following disclaimer. 1577118773Sthorpej * 2. Redistributions in binary form must reproduce the above copyright 1677118773Sthorpej * notice, this list of conditions and the following disclaimer in the 1777118773Sthorpej * documentation and/or other materials provided with the distribution. 1877118773Sthorpej * 1977118773Sthorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 2077118773Sthorpej * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 2177118773Sthorpej * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 2277118773Sthorpej * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2377118773Sthorpej * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 2477118773Sthorpej * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2577118773Sthorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 2677118773Sthorpej * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2777118773Sthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 2877118773Sthorpej * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2977118773Sthorpej * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 3077118773Sthorpej * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3177118773Sthorpej */ 3277118773Sthorpej 3377118773Sthorpej #include <sys/cdefs.h> 3477118773Sthorpej #if !defined(lint) 35*fd471022Sthorpej __RCSID("$NetBSD: threadpool.c,v 1.3 2018/12/26 18:54:20 thorpej Exp $"); 3677118773Sthorpej #endif /* !lint */ 3777118773Sthorpej 3877118773Sthorpej #include <sys/param.h> 3977118773Sthorpej #include <sys/condvar.h> 4077118773Sthorpej #include <sys/kernel.h> 4177118773Sthorpej #include <sys/kmem.h> 4277118773Sthorpej #include <sys/mutex.h> 4377118773Sthorpej #include <sys/threadpool.h> 4477118773Sthorpej 4577118773Sthorpej #include "kernspace.h" 4677118773Sthorpej 4777118773Sthorpej void 4877118773Sthorpej rumptest_threadpool_unbound_lifecycle(void) 4977118773Sthorpej { 50*fd471022Sthorpej struct threadpool *pool0, *pool1, *pool2; 5177118773Sthorpej int error; 5277118773Sthorpej 5377118773Sthorpej error = threadpool_get(&pool0, PRI_NONE); 5477118773Sthorpej KASSERT(error == 0); 5577118773Sthorpej 5677118773Sthorpej error = threadpool_get(&pool1, PRI_NONE); 5777118773Sthorpej KASSERT(error == 0); 5877118773Sthorpej 5977118773Sthorpej KASSERT(pool0 == pool1); 6077118773Sthorpej 6177118773Sthorpej error = threadpool_get(&pool2, PRI_KERNEL_RT); 6277118773Sthorpej KASSERT(error == 0); 6377118773Sthorpej 6477118773Sthorpej KASSERT(pool0 != pool2); 6577118773Sthorpej 6677118773Sthorpej threadpool_put(pool0, PRI_NONE); 6777118773Sthorpej threadpool_put(pool1, PRI_NONE); 6877118773Sthorpej threadpool_put(pool2, PRI_KERNEL_RT); 6977118773Sthorpej } 7077118773Sthorpej 7177118773Sthorpej void 7277118773Sthorpej rumptest_threadpool_percpu_lifecycle(void) 7377118773Sthorpej { 74*fd471022Sthorpej struct threadpool_percpu *pcpu0, *pcpu1, *pcpu2; 7577118773Sthorpej int error; 7677118773Sthorpej 7777118773Sthorpej error = threadpool_percpu_get(&pcpu0, PRI_NONE); 7877118773Sthorpej KASSERT(error == 0); 7977118773Sthorpej 8077118773Sthorpej error = threadpool_percpu_get(&pcpu1, PRI_NONE); 8177118773Sthorpej KASSERT(error == 0); 8277118773Sthorpej 8377118773Sthorpej KASSERT(pcpu0 == pcpu1); 8477118773Sthorpej 8577118773Sthorpej error = threadpool_percpu_get(&pcpu2, PRI_KERNEL_RT); 8677118773Sthorpej KASSERT(error == 0); 8777118773Sthorpej 8877118773Sthorpej KASSERT(pcpu0 != pcpu2); 8977118773Sthorpej 9077118773Sthorpej threadpool_percpu_put(pcpu0, PRI_NONE); 9177118773Sthorpej threadpool_percpu_put(pcpu1, PRI_NONE); 9277118773Sthorpej threadpool_percpu_put(pcpu2, PRI_KERNEL_RT); 9377118773Sthorpej } 9477118773Sthorpej 9577118773Sthorpej struct test_job_data { 9677118773Sthorpej kmutex_t mutex; 9777118773Sthorpej kcondvar_t cond; 9877118773Sthorpej unsigned int count; 99*fd471022Sthorpej struct threadpool_job job; 10077118773Sthorpej }; 10177118773Sthorpej 10277118773Sthorpej #define FINAL_COUNT 12345 10377118773Sthorpej 10477118773Sthorpej static void 105*fd471022Sthorpej test_job_func_schedule(struct threadpool_job *job) 10677118773Sthorpej { 10777118773Sthorpej struct test_job_data *data = 10877118773Sthorpej container_of(job, struct test_job_data, job); 10977118773Sthorpej 11077118773Sthorpej mutex_enter(&data->mutex); 11177118773Sthorpej KASSERT(data->count != FINAL_COUNT); 11277118773Sthorpej data->count++; 11377118773Sthorpej cv_broadcast(&data->cond); 11477118773Sthorpej threadpool_job_done(job); 11577118773Sthorpej mutex_exit(&data->mutex); 11677118773Sthorpej } 11777118773Sthorpej 11877118773Sthorpej static void 119*fd471022Sthorpej test_job_func_cancel(struct threadpool_job *job) 12077118773Sthorpej { 12177118773Sthorpej struct test_job_data *data = 12277118773Sthorpej container_of(job, struct test_job_data, job); 12377118773Sthorpej 12477118773Sthorpej mutex_enter(&data->mutex); 12577118773Sthorpej data->count = 1; 12677118773Sthorpej cv_broadcast(&data->cond); 12777118773Sthorpej while (data->count != FINAL_COUNT - 1) 12877118773Sthorpej cv_wait(&data->cond, &data->mutex); 12977118773Sthorpej data->count = FINAL_COUNT; 13077118773Sthorpej cv_broadcast(&data->cond); 13177118773Sthorpej threadpool_job_done(job); 13277118773Sthorpej mutex_exit(&data->mutex); 13377118773Sthorpej } 13477118773Sthorpej 13577118773Sthorpej static void 13677118773Sthorpej init_test_job_data(struct test_job_data *data, threadpool_job_fn_t fn) 13777118773Sthorpej { 13877118773Sthorpej mutex_init(&data->mutex, MUTEX_DEFAULT, IPL_NONE); 13977118773Sthorpej cv_init(&data->cond, "testjob"); 14077118773Sthorpej threadpool_job_init(&data->job, fn, &data->mutex, "testjob"); 14177118773Sthorpej data->count = 0; 14277118773Sthorpej } 14377118773Sthorpej 14477118773Sthorpej static void 14577118773Sthorpej fini_test_job_data(struct test_job_data *data) 14677118773Sthorpej { 14777118773Sthorpej threadpool_job_destroy(&data->job); 14877118773Sthorpej cv_destroy(&data->cond); 14977118773Sthorpej mutex_destroy(&data->mutex); 15077118773Sthorpej } 15177118773Sthorpej 15277118773Sthorpej void 15377118773Sthorpej rumptest_threadpool_unbound_schedule(void) 15477118773Sthorpej { 15577118773Sthorpej struct test_job_data data; 156*fd471022Sthorpej struct threadpool *pool; 15777118773Sthorpej int error; 15877118773Sthorpej 15977118773Sthorpej error = threadpool_get(&pool, PRI_NONE); 16077118773Sthorpej KASSERT(error == 0); 16177118773Sthorpej 16277118773Sthorpej init_test_job_data(&data, test_job_func_schedule); 16377118773Sthorpej 16477118773Sthorpej mutex_enter(&data.mutex); 16577118773Sthorpej while (data.count != FINAL_COUNT) { 16677118773Sthorpej threadpool_schedule_job(pool, &data.job); 16777118773Sthorpej error = cv_timedwait(&data.cond, &data.mutex, hz * 2); 16877118773Sthorpej KASSERT(error != EWOULDBLOCK); 16977118773Sthorpej } 17077118773Sthorpej mutex_exit(&data.mutex); 17177118773Sthorpej 17277118773Sthorpej fini_test_job_data(&data); 17377118773Sthorpej 17477118773Sthorpej threadpool_put(pool, PRI_NONE); 17577118773Sthorpej } 17677118773Sthorpej 17777118773Sthorpej void 17877118773Sthorpej rumptest_threadpool_percpu_schedule(void) 17977118773Sthorpej { 18077118773Sthorpej struct test_job_data data; 181*fd471022Sthorpej struct threadpool_percpu *pcpu; 182*fd471022Sthorpej struct threadpool *pool; 18377118773Sthorpej int error; 18477118773Sthorpej 18577118773Sthorpej error = threadpool_percpu_get(&pcpu, PRI_NONE); 18677118773Sthorpej KASSERT(error == 0); 18777118773Sthorpej 18877118773Sthorpej pool = threadpool_percpu_ref(pcpu); 18977118773Sthorpej 19077118773Sthorpej init_test_job_data(&data, test_job_func_schedule); 19177118773Sthorpej 19277118773Sthorpej mutex_enter(&data.mutex); 19377118773Sthorpej while (data.count != FINAL_COUNT) { 19477118773Sthorpej threadpool_schedule_job(pool, &data.job); 19577118773Sthorpej error = cv_timedwait(&data.cond, &data.mutex, hz * 2); 19677118773Sthorpej KASSERT(error != EWOULDBLOCK); 19777118773Sthorpej } 19877118773Sthorpej mutex_exit(&data.mutex); 19977118773Sthorpej 20077118773Sthorpej fini_test_job_data(&data); 20177118773Sthorpej 20277118773Sthorpej threadpool_percpu_put(pcpu, PRI_NONE); 20377118773Sthorpej } 20477118773Sthorpej 20577118773Sthorpej void 20677118773Sthorpej rumptest_threadpool_job_cancel(void) 20777118773Sthorpej { 20877118773Sthorpej struct test_job_data data; 209*fd471022Sthorpej struct threadpool *pool; 21077118773Sthorpej int error; 21177118773Sthorpej bool rv; 21277118773Sthorpej 21377118773Sthorpej error = threadpool_get(&pool, PRI_NONE); 21477118773Sthorpej KASSERT(error == 0); 21577118773Sthorpej 21677118773Sthorpej init_test_job_data(&data, test_job_func_cancel); 21777118773Sthorpej 21877118773Sthorpej mutex_enter(&data.mutex); 21977118773Sthorpej threadpool_schedule_job(pool, &data.job); 22077118773Sthorpej while (data.count == 0) 22177118773Sthorpej cv_wait(&data.cond, &data.mutex); 22277118773Sthorpej KASSERT(data.count == 1); 22377118773Sthorpej 22477118773Sthorpej /* Job is already running (and is not finished); this shold fail. */ 22577118773Sthorpej rv = threadpool_cancel_job_async(pool, &data.job); 22677118773Sthorpej KASSERT(rv == false); 22777118773Sthorpej 22877118773Sthorpej data.count = FINAL_COUNT - 1; 22977118773Sthorpej cv_broadcast(&data.cond); 23077118773Sthorpej 23177118773Sthorpej /* Now wait for the job to finish. */ 23277118773Sthorpej threadpool_cancel_job(pool, &data.job); 23377118773Sthorpej KASSERT(data.count == FINAL_COUNT); 23441d71c6bSthorpej mutex_exit(&data.mutex); 23541d71c6bSthorpej 23641d71c6bSthorpej fini_test_job_data(&data); 23741d71c6bSthorpej 23841d71c6bSthorpej threadpool_put(pool, PRI_NONE); 23977118773Sthorpej } 240