1 /* $OpenBSD: completion.h,v 1.10 2024/01/06 09:33:08 kettenis Exp $ */
2 /*
3 * Copyright (c) 2015, 2018 Mark Kettenis
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #ifndef _LINUX_COMPLETION_H
19 #define _LINUX_COMPLETION_H
20
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/mutex.h>
24 #include <linux/wait.h>
25
26 struct completion {
27 u_int done;
28 struct mutex lock;
29 };
30
31 #define DECLARE_COMPLETION_ONSTACK(name) \
32 struct completion name = { 0, MUTEX_INITIALIZER(IPL_TTY) }
33
34 static inline void
init_completion(struct completion * x)35 init_completion(struct completion *x)
36 {
37 x->done = 0;
38 mtx_init(&x->lock, IPL_TTY);
39 }
40
41 static inline void
reinit_completion(struct completion * x)42 reinit_completion(struct completion *x)
43 {
44 x->done = 0;
45 }
46
47 static inline u_long
wait_for_completion_timeout(struct completion * x,u_long timo)48 wait_for_completion_timeout(struct completion *x, u_long timo)
49 {
50 int ret;
51
52 KASSERT(!cold);
53
54 mtx_enter(&x->lock);
55 while (x->done == 0) {
56 ret = msleep(x, &x->lock, 0, "wfct", timo);
57 if (ret) {
58 mtx_leave(&x->lock);
59 /* timeout */
60 return 0;
61 }
62 }
63 if (x->done != UINT_MAX)
64 x->done--;
65 mtx_leave(&x->lock);
66
67 return 1;
68 }
69
70 static inline void
wait_for_completion(struct completion * x)71 wait_for_completion(struct completion *x)
72 {
73 KASSERT(!cold);
74
75 mtx_enter(&x->lock);
76 while (x->done == 0) {
77 msleep_nsec(x, &x->lock, 0, "wfcom", INFSLP);
78 }
79 if (x->done != UINT_MAX)
80 x->done--;
81 mtx_leave(&x->lock);
82 }
83
84 static inline u_long
wait_for_completion_interruptible(struct completion * x)85 wait_for_completion_interruptible(struct completion *x)
86 {
87 int ret;
88
89 KASSERT(!cold);
90
91 mtx_enter(&x->lock);
92 while (x->done == 0) {
93 ret = msleep_nsec(x, &x->lock, PCATCH, "wfci", INFSLP);
94 if (ret) {
95 mtx_leave(&x->lock);
96 if (ret == EWOULDBLOCK)
97 return 0;
98 return -ERESTARTSYS;
99 }
100 }
101 if (x->done != UINT_MAX)
102 x->done--;
103 mtx_leave(&x->lock);
104
105 return 0;
106 }
107
108 static inline u_long
wait_for_completion_interruptible_timeout(struct completion * x,u_long timo)109 wait_for_completion_interruptible_timeout(struct completion *x, u_long timo)
110 {
111 int ret;
112
113 KASSERT(!cold);
114
115 mtx_enter(&x->lock);
116 while (x->done == 0) {
117 ret = msleep(x, &x->lock, PCATCH, "wfcit", timo);
118 if (ret) {
119 mtx_leave(&x->lock);
120 if (ret == EWOULDBLOCK)
121 return 0;
122 return -ERESTARTSYS;
123 }
124 }
125 if (x->done != UINT_MAX)
126 x->done--;
127 mtx_leave(&x->lock);
128
129 return 1;
130 }
131
132 static inline void
complete(struct completion * x)133 complete(struct completion *x)
134 {
135 mtx_enter(&x->lock);
136 if (x->done != UINT_MAX)
137 x->done++;
138 mtx_leave(&x->lock);
139 wakeup_one(x);
140 }
141
142 static inline void
complete_all(struct completion * x)143 complete_all(struct completion *x)
144 {
145 mtx_enter(&x->lock);
146 x->done = UINT_MAX;
147 mtx_leave(&x->lock);
148 wakeup(x);
149 }
150
151 static inline bool
try_wait_for_completion(struct completion * x)152 try_wait_for_completion(struct completion *x)
153 {
154 mtx_enter(&x->lock);
155 if (x->done == 0) {
156 mtx_leave(&x->lock);
157 return false;
158 }
159 if (x->done != UINT_MAX)
160 x->done--;
161 mtx_leave(&x->lock);
162 return true;
163 }
164
165 #endif
166