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