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();
+}

Reply via email to