xref: /netbsd-src/tests/rump/kernspace/workqueue.c (revision 78e153c0eb7c01f6b2c9fa5714f1b47c07d65bbb)
1 /*	$NetBSD: workqueue.c,v 1.10 2023/08/10 22:20:20 riastradh Exp $	*/
2 
3 /*-
4  * Copyright (c) 2017 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 #if !defined(lint)
32 __RCSID("$NetBSD: workqueue.c,v 1.10 2023/08/10 22:20:20 riastradh Exp $");
33 #endif /* !lint */
34 
35 #include <sys/param.h>
36 #include <sys/condvar.h>
37 #include <sys/kernel.h>
38 #include <sys/kmem.h>
39 #include <sys/kthread.h>
40 #include <sys/mutex.h>
41 #include <sys/workqueue.h>
42 
43 #include "kernspace.h"
44 
45 struct test_softc {
46 	kmutex_t mtx;
47 	kcondvar_t cv;
48 	struct workqueue *wq;
49 	struct work wk;
50 	int counter;
51 	bool pause;
52 };
53 
54 static void
rump_work1(struct work * wk,void * arg)55 rump_work1(struct work *wk, void *arg)
56 {
57 	struct test_softc *sc = arg;
58 
59 	memset(wk, 0x5a, sizeof(*wk));
60 
61 	if (sc->pause)
62 		kpause("tstwk1", /*intr*/false, /*timo*/2, /*lock*/NULL);
63 
64 	mutex_enter(&sc->mtx);
65 	++sc->counter;
66 	cv_broadcast(&sc->cv);
67 	mutex_exit(&sc->mtx);
68 }
69 
70 static struct test_softc *
create_sc(void)71 create_sc(void)
72 {
73 	int rv;
74 	struct test_softc *sc;
75 
76 	sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
77 	mutex_init(&sc->mtx, MUTEX_DEFAULT, IPL_NONE);
78 	cv_init(&sc->cv, "rumpwqcv");
79 	rv = workqueue_create(&sc->wq, "rumpwq",
80 	    rump_work1, sc, PRI_SOFTNET, IPL_SOFTNET, 0);
81 	if (rv)
82 		panic("workqueue creation failed: %d", rv);
83 
84 	sc->counter = 0;
85 
86 	return sc;
87 }
88 
89 static void
destroy_sc(struct test_softc * sc)90 destroy_sc(struct test_softc *sc)
91 {
92 
93 	cv_destroy(&sc->cv);
94 	mutex_destroy(&sc->mtx);
95 	workqueue_destroy(sc->wq);
96 }
97 
98 void
rumptest_workqueue1()99 rumptest_workqueue1()
100 {
101 	struct test_softc *sc;
102 
103 	sc = create_sc();
104 
105 #define ITERATIONS 12435
106 	for (int i = 0; i < ITERATIONS; ++i) {
107 		int e;
108 		mutex_enter(&sc->mtx);
109 		workqueue_enqueue(sc->wq, &sc->wk, NULL);
110 		e = cv_timedwait(&sc->cv, &sc->mtx, hz * 2);
111 		if (e != 0)
112 			panic("cv_timedwait timed out (i=%d)", i);
113 		mutex_exit(&sc->mtx);
114 	}
115 
116 	KASSERT(sc->counter == ITERATIONS);
117 
118 	destroy_sc(sc);
119 #undef ITERATIONS
120 }
121 
122 void
rumptest_workqueue_wait(void)123 rumptest_workqueue_wait(void)
124 {
125 	struct test_softc *sc;
126 	struct work dummy;
127 
128 	sc = create_sc();
129 
130 #define ITERATIONS 12435
131 	for (size_t i = 0; i < ITERATIONS; ++i) {
132 		KASSERT(sc->counter == i);
133 		workqueue_enqueue(sc->wq, &sc->wk, NULL);
134 		workqueue_wait(sc->wq, &sc->wk);
135 		KASSERT(sc->counter == (i + 1));
136 	}
137 
138 	KASSERT(sc->counter == ITERATIONS);
139 
140 	/* Wait for a work that is not enqueued. Just return immediately. */
141 	workqueue_wait(sc->wq, &dummy);
142 
143 	destroy_sc(sc);
144 #undef ITERATIONS
145 }
146 
147 void
rumptest_workqueue_wait_pause(void)148 rumptest_workqueue_wait_pause(void)
149 {
150 	struct test_softc *sc;
151 	struct work dummy;
152 
153 	sc = create_sc();
154 	sc->pause = true;
155 
156 #define ITERATIONS 1
157 	for (size_t i = 0; i < ITERATIONS; ++i) {
158 		struct work wk;
159 
160 		KASSERT(sc->counter == i);
161 		workqueue_enqueue(sc->wq, &wk, NULL);
162 		workqueue_enqueue(sc->wq, &sc->wk, NULL);
163 		kpause("tstwk2", /*intr*/false, /*timo*/1, /*lock*/NULL);
164 		workqueue_wait(sc->wq, &sc->wk);
165 		workqueue_wait(sc->wq, &wk);
166 		KASSERT(sc->counter == (i + 2));
167 	}
168 
169 	KASSERT(sc->counter == 2*ITERATIONS);
170 
171 	/* Wait for a work that is not enqueued. Just return immediately. */
172 	workqueue_wait(sc->wq, &dummy);
173 
174 	destroy_sc(sc);
175 #undef ITERATIONS
176 }
177