Module Name: src Committed By: martin Date: Tue Jan 16 13:01:11 UTC 2018
Modified Files: src/distrib/sets/lists/debug [netbsd-8]: mi src/distrib/sets/lists/tests [netbsd-8]: mi src/share/man/man9 [netbsd-8]: workqueue.9 src/sys/kern [netbsd-8]: subr_workqueue.c src/sys/net [netbsd-8]: if_bridge.c if_spppsubr.c src/sys/sys [netbsd-8]: workqueue.h src/tests/rump/kernspace [netbsd-8]: Makefile kernspace.h src/tests/rump/rumpkern [netbsd-8]: Makefile Added Files: src/tests/rump/kernspace [netbsd-8]: workqueue.c src/tests/rump/rumpkern [netbsd-8]: t_workqueue.c Log Message: Pull up following revision(s) (requested by ozaki-r in ticket #497): tests/rump/rumpkern/Makefile: revision 1.16 tests/rump/kernspace/Makefile: revision 1.6 tests/rump/kernspace/workqueue.c: revision 1.1 tests/rump/kernspace/workqueue.c: revision 1.2 tests/rump/kernspace/workqueue.c: revision 1.3 tests/rump/kernspace/workqueue.c: revision 1.4 tests/rump/kernspace/workqueue.c: revision 1.5 tests/rump/kernspace/workqueue.c: revision 1.6 tests/rump/rumpkern/t_workqueue.c: revision 1.1 sys/sys/workqueue.h: revision 1.10 tests/rump/rumpkern/t_workqueue.c: revision 1.2 tests/rump/kernspace/kernspace.h: revision 1.5 tests/rump/kernspace/kernspace.h: revision 1.6 sys/net/if_bridge.c: revision 1.147 distrib/sets/lists/debug/mi: revision 1.225 sys/kern/subr_workqueue.c: revision 1.34 share/man/man9/workqueue.9: revision 1.12 sys/net/if_spppsubr.c: revision 1.178 distrib/sets/lists/tests/mi: revision 1.763 Add simple test for workqueue(9) Add declaration. build fix sorry, I forgot to commit this file. Tweak use of cv_timedwait - Handle its return value - Specify more appropriate time-out periods (2 ticks is too short) Fix a race condition on taking the mutex The workqueue worker can take the mutex before the tester tries to take it after calling workqueue_enqueue. If it happens, the worker calls cv_broadcast before the tester calls cv_timedwait and the tester will wait until the cv timed out Take the mutex before calling workqueue_enqueue so that the tester surely calls cv_timedwait before the worker calls cv_broadcast. The fix stabilizes the test, t_workqueue/workqueue1. Add workqueue_wait that waits for a specific work to finish The caller must ensure that no new work is enqueued before calling workqueue_wait. Note that Note that if the workqueue is WQ_PERCPU, the caller can enqueue a new work to another queue other than the waiting queue. Discussed on tech-kern@ Ensure the timer isn't running by using workqueue_wait Functionalize some routines to add new tests easily (NFC) Add a test case for workqueue_wait Fix build To generate a diff of this commit: cvs rdiff -u -r1.216.2.7 -r1.216.2.8 src/distrib/sets/lists/debug/mi cvs rdiff -u -r1.752.2.7 -r1.752.2.8 src/distrib/sets/lists/tests/mi cvs rdiff -u -r1.11 -r1.11.8.1 src/share/man/man9/workqueue.9 cvs rdiff -u -r1.33 -r1.33.30.1 src/sys/kern/subr_workqueue.c cvs rdiff -u -r1.134.6.5 -r1.134.6.6 src/sys/net/if_bridge.c cvs rdiff -u -r1.169.6.3 -r1.169.6.4 src/sys/net/if_spppsubr.c cvs rdiff -u -r1.9 -r1.9.100.1 src/sys/sys/workqueue.h cvs rdiff -u -r1.5 -r1.5.38.1 src/tests/rump/kernspace/Makefile cvs rdiff -u -r1.4 -r1.4.38.1 src/tests/rump/kernspace/kernspace.h cvs rdiff -u -r0 -r1.6.2.2 src/tests/rump/kernspace/workqueue.c cvs rdiff -u -r1.15 -r1.15.16.1 src/tests/rump/rumpkern/Makefile cvs rdiff -u -r0 -r1.2.2.2 src/tests/rump/rumpkern/t_workqueue.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/distrib/sets/lists/debug/mi diff -u src/distrib/sets/lists/debug/mi:1.216.2.7 src/distrib/sets/lists/debug/mi:1.216.2.8 --- src/distrib/sets/lists/debug/mi:1.216.2.7 Fri Dec 22 06:05:35 2017 +++ src/distrib/sets/lists/debug/mi Tue Jan 16 13:01:10 2018 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.216.2.7 2017/12/22 06:05:35 snj Exp $ +# $NetBSD: mi,v 1.216.2.8 2018/01/16 13:01:10 martin Exp $ ./etc/mtree/set.debug comp-sys-root ./usr/lib comp-sys-usr compatdir ./usr/lib/i18n/libBIG5_g.a comp-c-debuglib debuglib,compatfile @@ -2305,6 +2305,7 @@ ./usr/libdata/debug/usr/tests/rump/rumpkern/t_signals.debug tests-syscall-debug debug,atf,rump ./usr/libdata/debug/usr/tests/rump/rumpkern/t_threads.debug tests-syscall-debug debug,atf,rump ./usr/libdata/debug/usr/tests/rump/rumpkern/t_tsleep.debug tests-syscall-debug debug,atf,rump +./usr/libdata/debug/usr/tests/rump/rumpkern/t_workqueue.debug tests-syscall-debug debug,atf,rump ./usr/libdata/debug/usr/tests/rump/rumpkern/t_vm.debug tests-syscall-debug debug,atf,rump ./usr/libdata/debug/usr/tests/rump/rumpvfs/t_basic.debug tests-syscall-debug debug,atf,rump ./usr/libdata/debug/usr/tests/rump/rumpvfs/t_etfs.debug tests-syscall-debug debug,atf,rump Index: src/distrib/sets/lists/tests/mi diff -u src/distrib/sets/lists/tests/mi:1.752.2.7 src/distrib/sets/lists/tests/mi:1.752.2.8 --- src/distrib/sets/lists/tests/mi:1.752.2.7 Thu Dec 21 21:08:13 2017 +++ src/distrib/sets/lists/tests/mi Tue Jan 16 13:01:10 2018 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.752.2.7 2017/12/21 21:08:13 snj Exp $ +# $NetBSD: mi,v 1.752.2.8 2018/01/16 13:01:10 martin Exp $ # # Note: don't delete entries from here - mark them as "obsolete" instead. # @@ -3417,6 +3417,7 @@ ./usr/tests/rump/rumpkern/t_sp 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_workqueue tests-rump-tests atf,rump ./usr/tests/rump/rumpkern/t_vm tests-rump-tests atf,rump ./usr/tests/rump/rumpnet tests-rump-tests compattestfile,atf ./usr/tests/rump/rumpnet/Atffile tests-rump-tests atf,rump Index: src/share/man/man9/workqueue.9 diff -u src/share/man/man9/workqueue.9:1.11 src/share/man/man9/workqueue.9:1.11.8.1 --- src/share/man/man9/workqueue.9:1.11 Tue Oct 13 04:22:24 2015 +++ src/share/man/man9/workqueue.9 Tue Jan 16 13:01:10 2018 @@ -1,4 +1,4 @@ -.\" $NetBSD: workqueue.9,v 1.11 2015/10/13 04:22:24 riastradh Exp $ +.\" $NetBSD: workqueue.9,v 1.11.8.1 2018/01/16 13:01:10 martin Exp $ .\" .\" Copyright (c)2005 YAMAMOTO Takashi, .\" All rights reserved. @@ -25,7 +25,7 @@ .\" SUCH DAMAGE. .\" .\" ------------------------------------------------------------ -.Dd October 24, 2011 +.Dd December 28, 2017 .Dt WORKQUEUE 9 .Os .\" ------------------------------------------------------------ @@ -47,6 +47,10 @@ "struct workqueue *wq" "struct work *wk" "struct cpu_info *ci" .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .Ft void +.Fn workqueue_wait \ +"struct workqueue *wq" "struct work *wk" +.\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +.Ft void .Fn workqueue_destroy \ "struct workqueue *wq" .\" ------------------------------------------------------------ @@ -118,6 +122,19 @@ the framework. .Pp .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +.Fn workqueue_wait +waits for a specified work +.Fa wk +on the workqueue +.Fa wq +to finish. +The caller must ensure that no new work will be enqueued to the workqueue +beforehand. +Note that if the workqueue is +.Dv WQ_PERCPU , +the caller can enqueue a new work to another queue other than the waiting queue. +.Pp +.\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .Fn workqueue_destroy destroys a workqueue and frees associated resources. The caller should ensure that the workqueue has no work enqueued beforehand. Index: src/sys/kern/subr_workqueue.c diff -u src/sys/kern/subr_workqueue.c:1.33 src/sys/kern/subr_workqueue.c:1.33.30.1 --- src/sys/kern/subr_workqueue.c:1.33 Sun Oct 7 22:16:21 2012 +++ src/sys/kern/subr_workqueue.c Tue Jan 16 13:01:10 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: subr_workqueue.c,v 1.33 2012/10/07 22:16:21 matt Exp $ */ +/* $NetBSD: subr_workqueue.c,v 1.33.30.1 2018/01/16 13:01:10 martin Exp $ */ /*- * Copyright (c)2002, 2005, 2006, 2007 YAMAMOTO Takashi, @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: subr_workqueue.c,v 1.33 2012/10/07 22:16:21 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: subr_workqueue.c,v 1.33.30.1 2018/01/16 13:01:10 martin Exp $"); #include <sys/param.h> #include <sys/cpu.h> @@ -49,8 +49,10 @@ SIMPLEQ_HEAD(workqhead, work_impl); struct workqueue_queue { kmutex_t q_mutex; kcondvar_t q_cv; - struct workqhead q_queue; + struct workqhead q_queue_pending; + struct workqhead q_queue_running; lwp_t *q_worker; + work_impl_t *q_waiter; }; struct workqueue { @@ -115,24 +117,29 @@ workqueue_worker(void *cookie) q = workqueue_queue_lookup(wq, curlwp->l_cpu); for (;;) { - struct workqhead tmp; - /* * we violate abstraction of SIMPLEQ. */ -#if defined(DIAGNOSTIC) - tmp.sqh_last = (void *)POISON; -#endif /* defined(DIAGNOSTIC) */ - mutex_enter(&q->q_mutex); - while (SIMPLEQ_EMPTY(&q->q_queue)) + while (SIMPLEQ_EMPTY(&q->q_queue_pending)) cv_wait(&q->q_cv, &q->q_mutex); - tmp.sqh_first = q->q_queue.sqh_first; /* XXX */ - SIMPLEQ_INIT(&q->q_queue); + KASSERT(SIMPLEQ_EMPTY(&q->q_queue_running)); + q->q_queue_running.sqh_first = + q->q_queue_pending.sqh_first; /* XXX */ + SIMPLEQ_INIT(&q->q_queue_pending); mutex_exit(&q->q_mutex); - workqueue_runlist(wq, &tmp); + workqueue_runlist(wq, &q->q_queue_running); + + mutex_enter(&q->q_mutex); + KASSERT(!SIMPLEQ_EMPTY(&q->q_queue_running)); + SIMPLEQ_INIT(&q->q_queue_running); + if (__predict_false(q->q_waiter != NULL)) { + /* Wake up workqueue_wait */ + cv_signal(&q->q_cv); + } + mutex_exit(&q->q_mutex); } } @@ -159,7 +166,8 @@ workqueue_initqueue(struct workqueue *wq mutex_init(&q->q_mutex, MUTEX_DEFAULT, ipl); cv_init(&q->q_cv, wq->wq_name); - SIMPLEQ_INIT(&q->q_queue); + SIMPLEQ_INIT(&q->q_queue_pending); + SIMPLEQ_INIT(&q->q_queue_running); ktf = ((wq->wq_flags & WQ_MPSAFE) != 0 ? KTHREAD_MPSAFE : 0); if (wq->wq_prio < PRI_KERNEL) ktf |= KTHREAD_TS; @@ -194,7 +202,7 @@ workqueue_exit(struct work *wk, void *ar */ KASSERT(q->q_worker == curlwp); - KASSERT(SIMPLEQ_EMPTY(&q->q_queue)); + KASSERT(SIMPLEQ_EMPTY(&q->q_queue_pending)); mutex_enter(&q->q_mutex); q->q_worker = NULL; cv_signal(&q->q_cv); @@ -210,10 +218,10 @@ workqueue_finiqueue(struct workqueue *wq KASSERT(wq->wq_func == workqueue_exit); wqe.wqe_q = q; - KASSERT(SIMPLEQ_EMPTY(&q->q_queue)); + KASSERT(SIMPLEQ_EMPTY(&q->q_queue_pending)); KASSERT(q->q_worker != NULL); mutex_enter(&q->q_mutex); - SIMPLEQ_INSERT_TAIL(&q->q_queue, &wqe.wqe_wk, wk_entry); + SIMPLEQ_INSERT_TAIL(&q->q_queue_pending, &wqe.wqe_wk, wk_entry); cv_signal(&q->q_cv); while (q->q_worker != NULL) { cv_wait(&q->q_cv, &q->q_mutex); @@ -271,6 +279,64 @@ workqueue_create(struct workqueue **wqp, return error; } +static bool +workqueue_q_wait(struct workqueue_queue *q, work_impl_t *wk_target) +{ + work_impl_t *wk; + bool found = false; + + mutex_enter(&q->q_mutex); + again: + SIMPLEQ_FOREACH(wk, &q->q_queue_pending, wk_entry) { + if (wk == wk_target) + goto found; + } + SIMPLEQ_FOREACH(wk, &q->q_queue_running, wk_entry) { + if (wk == wk_target) + goto found; + } + found: + if (wk != NULL) { + found = true; + KASSERT(q->q_waiter == NULL); + q->q_waiter = wk; + cv_wait(&q->q_cv, &q->q_mutex); + goto again; + } + if (q->q_waiter != NULL) + q->q_waiter = NULL; + mutex_exit(&q->q_mutex); + + return found; +} + +/* + * Wait for a specified work to finish. The caller must ensure that no new + * work will be enqueued before calling workqueue_wait. Note that if the + * workqueue is WQ_PERCPU, the caller can enqueue a new work to another queue + * other than the waiting queue. + */ +void +workqueue_wait(struct workqueue *wq, struct work *wk) +{ + struct workqueue_queue *q; + bool found; + + if (ISSET(wq->wq_flags, WQ_PERCPU)) { + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + for (CPU_INFO_FOREACH(cii, ci)) { + q = workqueue_queue_lookup(wq, ci); + found = workqueue_q_wait(q, (work_impl_t *)wk); + if (found) + break; + } + } else { + q = workqueue_queue_lookup(wq, NULL); + (void) workqueue_q_wait(q, (work_impl_t *)wk); + } +} + void workqueue_destroy(struct workqueue *wq) { @@ -298,7 +364,8 @@ workqueue_enqueue(struct workqueue *wq, q = workqueue_queue_lookup(wq, ci); mutex_enter(&q->q_mutex); - SIMPLEQ_INSERT_TAIL(&q->q_queue, wk, wk_entry); + KASSERT(q->q_waiter == NULL); + SIMPLEQ_INSERT_TAIL(&q->q_queue_pending, wk, wk_entry); cv_signal(&q->q_cv); mutex_exit(&q->q_mutex); } Index: src/sys/net/if_bridge.c diff -u src/sys/net/if_bridge.c:1.134.6.5 src/sys/net/if_bridge.c:1.134.6.6 --- src/sys/net/if_bridge.c:1.134.6.5 Tue Jan 2 10:20:33 2018 +++ src/sys/net/if_bridge.c Tue Jan 16 13:01:10 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: if_bridge.c,v 1.134.6.5 2018/01/02 10:20:33 snj Exp $ */ +/* $NetBSD: if_bridge.c,v 1.134.6.6 2018/01/16 13:01:10 martin Exp $ */ /* * Copyright 2001 Wasabi Systems, Inc. @@ -80,7 +80,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.134.6.5 2018/01/02 10:20:33 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.134.6.6 2018/01/16 13:01:10 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_bridge_ipf.h" @@ -1363,7 +1363,8 @@ bridge_stop(struct ifnet *ifp, int disab KASSERT((ifp->if_flags & IFF_RUNNING) != 0); ifp->if_flags &= ~IFF_RUNNING; - callout_stop(&sc->sc_brcallout); + callout_halt(&sc->sc_brcallout, NULL); + workqueue_wait(sc->sc_rtage_wq, &sc->sc_rtage_wk); bstp_stop(sc); bridge_rtflush(sc, IFBF_FLUSHDYN); } Index: src/sys/net/if_spppsubr.c diff -u src/sys/net/if_spppsubr.c:1.169.6.3 src/sys/net/if_spppsubr.c:1.169.6.4 --- src/sys/net/if_spppsubr.c:1.169.6.3 Tue Jan 2 10:20:33 2018 +++ src/sys/net/if_spppsubr.c Tue Jan 16 13:01:10 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: if_spppsubr.c,v 1.169.6.3 2018/01/02 10:20:33 snj Exp $ */ +/* $NetBSD: if_spppsubr.c,v 1.169.6.4 2018/01/16 13:01:10 martin Exp $ */ /* * Synchronous PPP/Cisco link level subroutines. @@ -41,7 +41,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_spppsubr.c,v 1.169.6.3 2018/01/02 10:20:33 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_spppsubr.c,v 1.169.6.4 2018/01/16 13:01:10 martin Exp $"); #if defined(_KERNEL_OPT) #include "opt_inet.h" @@ -1073,6 +1073,7 @@ sppp_detach(struct ifnet *ifp) /* to avoid workqueue enqueued */ atomic_swap_uint(&sp->ipcp.update_addrs_enqueued, 1); + workqueue_wait(sp->ipcp.update_addrs_wq, &sp->ipcp.update_addrs_wk); workqueue_destroy(sp->ipcp.update_addrs_wq); pcq_destroy(sp->ipcp.update_addrs_q); Index: src/sys/sys/workqueue.h diff -u src/sys/sys/workqueue.h:1.9 src/sys/sys/workqueue.h:1.9.100.1 --- src/sys/sys/workqueue.h:1.9 Fri Oct 19 12:16:48 2007 +++ src/sys/sys/workqueue.h Tue Jan 16 13:01:10 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: workqueue.h,v 1.9 2007/10/19 12:16:48 ad Exp $ */ +/* $NetBSD: workqueue.h,v 1.9.100.1 2018/01/16 13:01:10 martin Exp $ */ /*- * Copyright (c)2002, 2005 YAMAMOTO Takashi, @@ -51,6 +51,7 @@ struct workqueue; int workqueue_create(struct workqueue **, const char *, void (*)(struct work *, void *), void *, pri_t, int, int); void workqueue_destroy(struct workqueue *); +void workqueue_wait(struct workqueue *, struct work *); void workqueue_enqueue(struct workqueue *, struct work *, struct cpu_info *); Index: src/tests/rump/kernspace/Makefile diff -u src/tests/rump/kernspace/Makefile:1.5 src/tests/rump/kernspace/Makefile:1.5.38.1 --- src/tests/rump/kernspace/Makefile:1.5 Fri Jan 14 13:08:00 2011 +++ src/tests/rump/kernspace/Makefile Tue Jan 16 13:01:10 2018 @@ -1,10 +1,10 @@ -# $NetBSD: Makefile,v 1.5 2011/01/14 13:08:00 pooka Exp $ +# $NetBSD: Makefile,v 1.5.38.1 2018/01/16 13:01:10 martin Exp $ # .include <bsd.own.mk> LIB= kernspace -SRCS= thread.c busypage.c tsleep.c alloc.c lockme.c sendsig.c +SRCS= thread.c busypage.c tsleep.c alloc.c lockme.c workqueue.c sendsig.c RUMPTOP=${NETBSDSRCDIR}/sys/rump Index: src/tests/rump/kernspace/kernspace.h diff -u src/tests/rump/kernspace/kernspace.h:1.4 src/tests/rump/kernspace/kernspace.h:1.4.38.1 --- src/tests/rump/kernspace/kernspace.h:1.4 Fri Jan 14 13:08:00 2011 +++ src/tests/rump/kernspace/kernspace.h Tue Jan 16 13:01:10 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: kernspace.h,v 1.4 2011/01/14 13:08:00 pooka Exp $ */ +/* $NetBSD: kernspace.h,v 1.4.38.1 2018/01/16 13:01:10 martin Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -40,6 +40,8 @@ void rumptest_thread(void); void rumptest_tsleep(void); void rumptest_alloc(size_t); void rumptest_lockme(enum locktest); +void rumptest_workqueue1(void); +void rumptest_workqueue_wait(void); void rumptest_sendsig(char *); void rumptest_localsig(int); Index: src/tests/rump/rumpkern/Makefile diff -u src/tests/rump/rumpkern/Makefile:1.15 src/tests/rump/rumpkern/Makefile:1.15.16.1 --- src/tests/rump/rumpkern/Makefile:1.15 Tue Jun 10 04:28:40 2014 +++ src/tests/rump/rumpkern/Makefile Tue Jan 16 13:01:10 2018 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.15 2014/06/10 04:28:40 he Exp $ +# $NetBSD: Makefile,v 1.15.16.1 2018/01/16 13:01:10 martin Exp $ .include <bsd.own.mk> @@ -12,6 +12,7 @@ TESTS_C+= t_modlinkset TESTS_C+= t_signals TESTS_C+= t_threads TESTS_C+= t_tsleep +TESTS_C+= t_workqueue TESTS_C+= t_vm TESTS_SH= t_sp Added files: Index: src/tests/rump/kernspace/workqueue.c diff -u /dev/null src/tests/rump/kernspace/workqueue.c:1.6.2.2 --- /dev/null Tue Jan 16 13:01:11 2018 +++ src/tests/rump/kernspace/workqueue.c Tue Jan 16 13:01:10 2018 @@ -0,0 +1,139 @@ +/* $NetBSD: workqueue.c,v 1.6.2.2 2018/01/16 13:01:10 martin Exp $ */ + +/*- + * Copyright (c) 2017 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/cdefs.h> +#if !defined(lint) +__RCSID("$NetBSD: workqueue.c,v 1.6.2.2 2018/01/16 13:01:10 martin Exp $"); +#endif /* !lint */ + +#include <sys/param.h> +#include <sys/condvar.h> +#include <sys/kernel.h> +#include <sys/kmem.h> +#include <sys/kthread.h> +#include <sys/mutex.h> +#include <sys/workqueue.h> + +#include "kernspace.h" + +struct test_softc { + kmutex_t mtx; + kcondvar_t cv; + struct workqueue *wq; + struct work wk; + int counter; +}; + +static void +rump_work1(struct work *wk, void *arg) +{ + struct test_softc *sc = arg; + + mutex_enter(&sc->mtx); + ++sc->counter; + cv_broadcast(&sc->cv); + mutex_exit(&sc->mtx); +} + +static struct test_softc * +create_sc(void) +{ + int rv; + struct test_softc *sc; + + sc = kmem_zalloc(sizeof(*sc), KM_SLEEP); + mutex_init(&sc->mtx, MUTEX_DEFAULT, IPL_NONE); + cv_init(&sc->cv, "rumpwqcv"); + rv = workqueue_create(&sc->wq, "rumpwq", + rump_work1, sc, PRI_SOFTNET, IPL_SOFTNET, 0); + if (rv) + panic("workqueue creation failed: %d", rv); + + sc->counter = 0; + + return sc; +} + +static void +destroy_sc(struct test_softc *sc) +{ + + cv_destroy(&sc->cv); + mutex_destroy(&sc->mtx); + workqueue_destroy(sc->wq); +} + +void +rumptest_workqueue1() +{ + struct test_softc *sc; + + sc = create_sc(); + +#define ITERATIONS 12435 + for (int i = 0; i < ITERATIONS; ++i) { + int e; + mutex_enter(&sc->mtx); + workqueue_enqueue(sc->wq, &sc->wk, NULL); + e = cv_timedwait(&sc->cv, &sc->mtx, hz * 2); + if (e != 0) + panic("cv_timedwait timed out (i=%d)", i); + mutex_exit(&sc->mtx); + } + + KASSERT(sc->counter == ITERATIONS); + + destroy_sc(sc); +#undef ITERATIONS +} + +void +rumptest_workqueue_wait(void) +{ + struct test_softc *sc; + struct work dummy; + + sc = create_sc(); + +#define ITERATIONS 12435 + for (size_t i = 0; i < ITERATIONS; ++i) { + KASSERT(sc->counter == i); + workqueue_enqueue(sc->wq, &sc->wk, NULL); + workqueue_wait(sc->wq, &sc->wk); + KASSERT(sc->counter == (i + 1)); + } + + KASSERT(sc->counter == ITERATIONS); + + /* Wait for a work that is not enqueued. Just return immediately. */ + workqueue_wait(sc->wq, &dummy); + + destroy_sc(sc); +#undef ITERATIONS +} Index: src/tests/rump/rumpkern/t_workqueue.c diff -u /dev/null src/tests/rump/rumpkern/t_workqueue.c:1.2.2.2 --- /dev/null Tue Jan 16 13:01:11 2018 +++ src/tests/rump/rumpkern/t_workqueue.c Tue Jan 16 13:01:10 2018 @@ -0,0 +1,81 @@ +/* $NetBSD: t_workqueue.c,v 1.2.2.2 2018/01/16 13:01:10 martin Exp $ */ + +/*- + * Copyright (c) 2017 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(workqueue1); +ATF_TC_HEAD(workqueue1, tc) +{ + + atf_tc_set_md_var(tc, "descr", "Checks workqueue basics"); +} + +ATF_TC_BODY(workqueue1, tc) +{ + + rump_init(); + + rump_schedule(); + rumptest_workqueue1(); /* panics if fails */ + rump_unschedule(); +} + +ATF_TC(workqueue_wait); +ATF_TC_HEAD(workqueue_wait, tc) +{ + + atf_tc_set_md_var(tc, "descr", "Checks workqueue_wait"); +} + +ATF_TC_BODY(workqueue_wait, tc) +{ + + rump_init(); + + rump_schedule(); + rumptest_workqueue_wait(); /* panics if fails */ + rump_unschedule(); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, workqueue1); + ATF_TP_ADD_TC(tp, workqueue_wait); + + return atf_no_error(); +}