1 /* $NetBSD: task_barrier.h,v 1.1 2021/12/19 10:58:29 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2020 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 CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #ifndef _DRM_TASK_BARRIER_H_
30 #define _DRM_TASK_BARRIER_H_
31
32 #include <sys/condvar.h>
33 #include <sys/mutex.h>
34
35 struct task_barrier {
36 kmutex_t tb_lock;
37 kcondvar_t tb_cv;
38 unsigned tb_cur;
39 unsigned tb_gen;
40 unsigned tb_max;
41 };
42
43 static inline void
task_barrier_init(struct task_barrier * tb)44 task_barrier_init(struct task_barrier *tb)
45 {
46
47 mutex_init(&tb->tb_lock, MUTEX_DEFAULT, IPL_VM);
48 cv_init(&tb->tb_cv, "taskbar");
49 tb->tb_cur = 0;
50 tb->tb_gen = 0;
51 tb->tb_max = 0;
52 }
53
54 static inline void
task_barrier_destroy(struct task_barrier * tb)55 task_barrier_destroy(struct task_barrier *tb)
56 {
57
58 KASSERT(tb->tb_cur == 0);
59 cv_destroy(&tb->tb_cv);
60 mutex_destroy(&tb->tb_lock);
61 }
62
63 static inline void
task_barrier_add_task(struct task_barrier * tb)64 task_barrier_add_task(struct task_barrier *tb)
65 {
66
67 tb->tb_max++;
68 }
69
70 static inline void
task_barrier_rem_task(struct task_barrier * tb)71 task_barrier_rem_task(struct task_barrier *tb)
72 {
73
74 tb->tb_max--;
75 }
76
77 static inline void
task_barrier_enter(struct task_barrier * tb)78 task_barrier_enter(struct task_barrier *tb)
79 {
80
81 mutex_enter(&tb->tb_lock);
82 KASSERT(tb->tb_cur < tb->tb_max);
83 if (++tb->tb_cur < tb->tb_max) {
84 unsigned gen = tb->tb_gen;
85 do {
86 cv_wait(&tb->tb_cv, &tb->tb_lock);
87 } while (gen == tb->tb_gen);
88 } else {
89 tb->tb_gen++;
90 cv_broadcast(&tb->tb_cv);
91 }
92 mutex_exit(&tb->tb_lock);
93 }
94
95 static inline void
task_barrier_exit(struct task_barrier * tb)96 task_barrier_exit(struct task_barrier *tb)
97 {
98
99 mutex_enter(&tb->tb_lock);
100 KASSERT(tb->tb_cur > 0);
101 if (--tb->tb_cur > 0) {
102 unsigned gen = tb->tb_gen;
103 do {
104 cv_wait(&tb->tb_cv, &tb->tb_lock);
105 } while (gen == tb->tb_gen);
106 } else {
107 tb->tb_gen++;
108 cv_broadcast(&tb->tb_cv);
109 }
110 }
111
112 static inline void
task_barrier_full(struct task_barrier * tb)113 task_barrier_full(struct task_barrier *tb)
114 {
115
116 task_barrier_enter(tb);
117 task_barrier_exit(tb);
118 }
119
120 #endif /* _DRM_TASK_BARRIER_H_ */
121