Add rump-based test cases for threadpool(9).

This commit is contained in:
thorpej 2018-12-24 21:42:05 +00:00
parent c40d4bbfb3
commit 77118773d1
6 changed files with 387 additions and 6 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.799 2018/12/24 16:58:54 thorpej Exp $
# $NetBSD: mi,v 1.800 2018/12/24 21:42:05 thorpej Exp $
#
# Note: don't delete entries from here - mark them as "obsolete" instead.
#
@ -3468,6 +3468,7 @@
./usr/tests/rump/rumpkern/t_modlinkset tests-rump-tests atf,rump
./usr/tests/rump/rumpkern/t_signals tests-rump-tests atf,rump
./usr/tests/rump/rumpkern/t_sp tests-rump-tests atf,rump
./usr/tests/rump/rumpkern/t_threadpool tests-rump-tests atf,rump
./usr/tests/rump/rumpkern/t_threads tests-rump-tests atf,rump
./usr/tests/rump/rumpkern/t_tsleep tests-rump-tests atf,rump
./usr/tests/rump/rumpkern/t_vm tests-rump-tests atf,rump

View File

@ -1,10 +1,11 @@
# $NetBSD: Makefile,v 1.6 2017/09/29 12:42:36 maya Exp $
# $NetBSD: Makefile,v 1.7 2018/12/24 21:42:05 thorpej Exp $
#
.include <bsd.own.mk>
LIB= kernspace
SRCS= thread.c busypage.c tsleep.c alloc.c lockme.c workqueue.c sendsig.c
SRCS= thread.c threadpool.c busypage.c tsleep.c alloc.c lockme.c \
workqueue.c sendsig.c
RUMPTOP=${NETBSDSRCDIR}/sys/rump

View File

@ -1,7 +1,7 @@
/* $NetBSD: kernspace.h,v 1.6 2017/12/28 07:10:25 ozaki-r Exp $ */
/* $NetBSD: kernspace.h,v 1.7 2018/12/24 21:42:05 thorpej Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* Copyright (c) 2010, 2018 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -46,4 +46,10 @@ void rumptest_workqueue_wait(void);
void rumptest_sendsig(char *);
void rumptest_localsig(int);
void rumptest_threadpool_unbound_lifecycle(void);
void rumptest_threadpool_percpu_lifecycle(void);
void rumptest_threadpool_unbound_schedule(void);
void rumptest_threadpool_percpu_schedule(void);
void rumptest_threadpool_job_cancel(void);
#endif /* _TESTS_RUMP_KERNSPACE_KERNSPACE_H_ */

View File

@ -0,0 +1,234 @@
/* $NetBSD: threadpool.c,v 1.1 2018/12/24 21:42:05 thorpej Exp $ */
/*-
* Copyright (c) 2018 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#if !defined(lint)
__RCSID("$NetBSD: threadpool.c,v 1.1 2018/12/24 21:42:05 thorpej Exp $");
#endif /* !lint */
#include <sys/param.h>
#include <sys/condvar.h>
#include <sys/kernel.h>
#include <sys/kmem.h>
#include <sys/mutex.h>
#include <sys/threadpool.h>
#include "kernspace.h"
void
rumptest_threadpool_unbound_lifecycle(void)
{
threadpool_t *pool0, *pool1, *pool2;
int error;
error = threadpool_get(&pool0, PRI_NONE);
KASSERT(error == 0);
error = threadpool_get(&pool1, PRI_NONE);
KASSERT(error == 0);
KASSERT(pool0 == pool1);
error = threadpool_get(&pool2, PRI_KERNEL_RT);
KASSERT(error == 0);
KASSERT(pool0 != pool2);
threadpool_put(pool0, PRI_NONE);
threadpool_put(pool1, PRI_NONE);
threadpool_put(pool2, PRI_KERNEL_RT);
}
void
rumptest_threadpool_percpu_lifecycle(void)
{
threadpool_percpu_t *pcpu0, *pcpu1, *pcpu2;
int error;
error = threadpool_percpu_get(&pcpu0, PRI_NONE);
KASSERT(error == 0);
error = threadpool_percpu_get(&pcpu1, PRI_NONE);
KASSERT(error == 0);
KASSERT(pcpu0 == pcpu1);
error = threadpool_percpu_get(&pcpu2, PRI_KERNEL_RT);
KASSERT(error == 0);
KASSERT(pcpu0 != pcpu2);
threadpool_percpu_put(pcpu0, PRI_NONE);
threadpool_percpu_put(pcpu1, PRI_NONE);
threadpool_percpu_put(pcpu2, PRI_KERNEL_RT);
}
struct test_job_data {
kmutex_t mutex;
kcondvar_t cond;
unsigned int count;
threadpool_job_t job;
};
#define FINAL_COUNT 12345
static void
test_job_func_schedule(threadpool_job_t *job)
{
struct test_job_data *data =
container_of(job, struct test_job_data, job);
mutex_enter(&data->mutex);
KASSERT(data->count != FINAL_COUNT);
data->count++;
cv_broadcast(&data->cond);
threadpool_job_done(job);
mutex_exit(&data->mutex);
}
static void
test_job_func_cancel(threadpool_job_t *job)
{
struct test_job_data *data =
container_of(job, struct test_job_data, job);
mutex_enter(&data->mutex);
data->count = 1;
cv_broadcast(&data->cond);
while (data->count != FINAL_COUNT - 1)
cv_wait(&data->cond, &data->mutex);
data->count = FINAL_COUNT;
cv_broadcast(&data->cond);
threadpool_job_done(job);
mutex_exit(&data->mutex);
}
static void
init_test_job_data(struct test_job_data *data, threadpool_job_fn_t fn)
{
mutex_init(&data->mutex, MUTEX_DEFAULT, IPL_NONE);
cv_init(&data->cond, "testjob");
threadpool_job_init(&data->job, fn, &data->mutex, "testjob");
data->count = 0;
}
static void
fini_test_job_data(struct test_job_data *data)
{
threadpool_job_destroy(&data->job);
cv_destroy(&data->cond);
mutex_destroy(&data->mutex);
}
void
rumptest_threadpool_unbound_schedule(void)
{
struct test_job_data data;
threadpool_t *pool;
int error;
error = threadpool_get(&pool, PRI_NONE);
KASSERT(error == 0);
init_test_job_data(&data, test_job_func_schedule);
mutex_enter(&data.mutex);
while (data.count != FINAL_COUNT) {
threadpool_schedule_job(pool, &data.job);
error = cv_timedwait(&data.cond, &data.mutex, hz * 2);
KASSERT(error != EWOULDBLOCK);
}
mutex_exit(&data.mutex);
fini_test_job_data(&data);
threadpool_put(pool, PRI_NONE);
}
void
rumptest_threadpool_percpu_schedule(void)
{
struct test_job_data data;
threadpool_percpu_t *pcpu;
threadpool_t *pool;
int error;
error = threadpool_percpu_get(&pcpu, PRI_NONE);
KASSERT(error == 0);
pool = threadpool_percpu_ref(pcpu);
init_test_job_data(&data, test_job_func_schedule);
mutex_enter(&data.mutex);
while (data.count != FINAL_COUNT) {
threadpool_schedule_job(pool, &data.job);
error = cv_timedwait(&data.cond, &data.mutex, hz * 2);
KASSERT(error != EWOULDBLOCK);
}
mutex_exit(&data.mutex);
fini_test_job_data(&data);
threadpool_percpu_put(pcpu, PRI_NONE);
}
void
rumptest_threadpool_job_cancel(void)
{
struct test_job_data data;
threadpool_t *pool;
int error;
bool rv;
error = threadpool_get(&pool, PRI_NONE);
KASSERT(error == 0);
init_test_job_data(&data, test_job_func_cancel);
mutex_enter(&data.mutex);
threadpool_schedule_job(pool, &data.job);
while (data.count == 0)
cv_wait(&data.cond, &data.mutex);
KASSERT(data.count == 1);
/* Job is already running (and is not finished); this shold fail. */
rv = threadpool_cancel_job_async(pool, &data.job);
KASSERT(rv == false);
data.count = FINAL_COUNT - 1;
cv_broadcast(&data.cond);
/* Now wait for the job to finish. */
threadpool_cancel_job(pool, &data.job);
KASSERT(data.count == FINAL_COUNT);
}

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.16 2017/09/29 12:42:37 maya Exp $
# $NetBSD: Makefile,v 1.17 2018/12/24 21:42:05 thorpej Exp $
.include <bsd.own.mk>
@ -11,6 +11,7 @@ TESTS_C+= t_modcmd
TESTS_C+= t_modlinkset
TESTS_C+= t_signals
TESTS_C+= t_threads
TESTS_C+= t_threadpool
TESTS_C+= t_tsleep
TESTS_C+= t_workqueue
TESTS_C+= t_vm

View File

@ -0,0 +1,138 @@
/* $NetBSD: t_threadpool.c,v 1.1 2018/12/24 21:42:05 thorpej Exp $ */
/*-
* Copyright (c) 2018 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/mount.h>
#include <sys/sysctl.h>
#include <rump/rump.h>
#include <atf-c.h>
#include "h_macros.h"
#include "../kernspace/kernspace.h"
ATF_TC(threadpool_unbound_lifecycle);
ATF_TC_HEAD(threadpool_unbound_lifecycle, tc)
{
atf_tc_set_md_var(tc, "descr", "Tests unbound threadpool lifecycle");
}
ATF_TC_BODY(threadpool_unbound_lifecycle, tc)
{
rump_init();
rump_schedule();
rumptest_threadpool_unbound_lifecycle(); /* panics if fails */
rump_unschedule();
}
ATF_TC(threadpool_percpu_lifecycle);
ATF_TC_HEAD(threadpool_percpu_lifecycle, tc)
{
atf_tc_set_md_var(tc, "descr", "Tests percpu threadpool lifecycle");
}
ATF_TC_BODY(threadpool_percpu_lifecycle, tc)
{
rump_init();
rump_schedule();
rumptest_threadpool_percpu_lifecycle(); /* panics if fails */
rump_unschedule();
}
ATF_TC(threadpool_unbound_schedule);
ATF_TC_HEAD(threadpool_unbound_schedule, tc)
{
atf_tc_set_md_var(tc, "descr",
"Tests scheduling on unbound threadpools");
}
ATF_TC_BODY(threadpool_unbound_schedule, tc)
{
rump_init();
rump_schedule();
rumptest_threadpool_unbound_schedule(); /* panics if fails */
rump_unschedule();
}
ATF_TC(threadpool_percpu_schedule);
ATF_TC_HEAD(threadpool_percpu_schedule, tc)
{
atf_tc_set_md_var(tc, "descr",
"Tests scheduling on percpu threadpools");
}
ATF_TC_BODY(threadpool_percpu_schedule, tc)
{
rump_init();
rump_schedule();
rumptest_threadpool_percpu_schedule(); /* panics if fails */
rump_unschedule();
}
ATF_TC(threadpool_job_cancel);
ATF_TC_HEAD(threadpool_job_cancel, tc)
{
atf_tc_set_md_var(tc, "descr",
"Tests synchronizing with job cancellation");
}
ATF_TC_BODY(threadpool_job_cancel, tc)
{
rump_init();
rump_schedule();
rumptest_threadpool_job_cancel(); /* panics if fails */
rump_unschedule();
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, threadpool_unbound_lifecycle);
ATF_TP_ADD_TC(tp, threadpool_percpu_lifecycle);
ATF_TP_ADD_TC(tp, threadpool_unbound_schedule);
ATF_TP_ADD_TC(tp, threadpool_percpu_schedule);
ATF_TP_ADD_TC(tp, threadpool_job_cancel);
return atf_no_error();
}