xref: /netbsd-src/tests/rump/kernspace/threadpool.c (revision fd47102229ecaef663b9f3512d24ca68686cd183)
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