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
26struct 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
34static inline void
35init_completion(struct completion *x)
36{
37	x->done = 0;
38	mtx_init(&x->lock, IPL_TTY);
39}
40
41static inline void
42reinit_completion(struct completion *x)
43{
44	x->done = 0;
45}
46
47static inline u_long
48wait_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
70static inline void
71wait_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
84static inline u_long
85wait_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
108static inline u_long
109wait_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
132static inline void
133complete(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
142static inline void
143complete_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
151static inline bool
152try_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