xref: /freebsd/sys/dev/ntsync/ntsync.c (revision 03ca6dbdb80da79408f135d823fbd9a00fd4f25b)
1*03ca6dbdSKonstantin Belousov /*
2*03ca6dbdSKonstantin Belousov  * SPDX-License-Identifier: BSD-2-Clause
3*03ca6dbdSKonstantin Belousov  *
4*03ca6dbdSKonstantin Belousov  * Copyright 2026 The FreeBSD Foundation
5*03ca6dbdSKonstantin Belousov  *
6*03ca6dbdSKonstantin Belousov  * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
7*03ca6dbdSKonstantin Belousov  * under sponsorship from the FreeBSD Foundation.
8*03ca6dbdSKonstantin Belousov  */
9*03ca6dbdSKonstantin Belousov 
10*03ca6dbdSKonstantin Belousov #include <sys/systm.h>
11*03ca6dbdSKonstantin Belousov #include <sys/conf.h>
12*03ca6dbdSKonstantin Belousov #include <sys/fcntl.h>
13*03ca6dbdSKonstantin Belousov #include <sys/file.h>
14*03ca6dbdSKonstantin Belousov #include <sys/filedesc.h>
15*03ca6dbdSKonstantin Belousov #include <sys/kernel.h>
16*03ca6dbdSKonstantin Belousov #include <sys/limits.h>
17*03ca6dbdSKonstantin Belousov #include <sys/malloc.h>
18*03ca6dbdSKonstantin Belousov #include <sys/module.h>
19*03ca6dbdSKonstantin Belousov #include <sys/proc.h>
20*03ca6dbdSKonstantin Belousov #include <sys/stat.h>
21*03ca6dbdSKonstantin Belousov #include <sys/sysent.h>
22*03ca6dbdSKonstantin Belousov #include <dev/ntsync/ntsyncvar.h>
23*03ca6dbdSKonstantin Belousov 
24*03ca6dbdSKonstantin Belousov static struct cdev *ntsync_cdev;
25*03ca6dbdSKonstantin Belousov MALLOC_DEFINE(M_NTSYNC, "ntsync", "ntsync");
26*03ca6dbdSKonstantin Belousov 
27*03ca6dbdSKonstantin Belousov static void ntsync_free_priv(struct ntsync_priv *priv);
28*03ca6dbdSKonstantin Belousov 
29*03ca6dbdSKonstantin Belousov /*
30*03ca6dbdSKonstantin Belousov  * Returning error from an ioctl handler prevents the generic ioctl
31*03ca6dbdSKonstantin Belousov  * code from copying out the result.  Use direct access to ioctl(2)
32*03ca6dbdSKonstantin Belousov  * args to get the parameters block pointer to implement Linux
33*03ca6dbdSKonstantin Belousov  * semantic of both returning an error and updating the parameters
34*03ca6dbdSKonstantin Belousov  * block.
35*03ca6dbdSKonstantin Belousov  */
36*03ca6dbdSKonstantin Belousov static int
37*03ca6dbdSKonstantin Belousov ntsync_ioctl_copyout(struct thread *td, const void *ptr, size_t sz)
38*03ca6dbdSKonstantin Belousov {
39*03ca6dbdSKonstantin Belousov 	void *uptr;
40*03ca6dbdSKonstantin Belousov 
41*03ca6dbdSKonstantin Belousov 	if (SV_PROC_ABI(td->td_proc) != SV_ABI_FREEBSD)
42*03ca6dbdSKonstantin Belousov 		return (0);
43*03ca6dbdSKonstantin Belousov 	uptr = (void *)(uintptr_t)td->td_sa.args[2];
44*03ca6dbdSKonstantin Belousov 	return (copyout(ptr, uptr, sz));
45*03ca6dbdSKonstantin Belousov }
46*03ca6dbdSKonstantin Belousov 
47*03ca6dbdSKonstantin Belousov static bool
48*03ca6dbdSKonstantin Belousov ntsync_wait_any(struct ntsync_wait_state *state)
49*03ca6dbdSKonstantin Belousov {
50*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
51*03ca6dbdSKonstantin Belousov 	int i;
52*03ca6dbdSKonstantin Belousov 
53*03ca6dbdSKonstantin Belousov 	MPASS(state->any);
54*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(state->owner);
55*03ca6dbdSKonstantin Belousov 
56*03ca6dbdSKonstantin Belousov 	for (i = 0; i < state->obj_count; i++) {
57*03ca6dbdSKonstantin Belousov 		obj = state->objs[i];
58*03ca6dbdSKonstantin Belousov 		if (obj->is_signaled(obj, state, i)) {
59*03ca6dbdSKonstantin Belousov 			state->index = i;
60*03ca6dbdSKonstantin Belousov 			obj->consume(obj, state, state->index);
61*03ca6dbdSKonstantin Belousov 			return (true);
62*03ca6dbdSKonstantin Belousov 		}
63*03ca6dbdSKonstantin Belousov 	}
64*03ca6dbdSKonstantin Belousov 	return (false);
65*03ca6dbdSKonstantin Belousov }
66*03ca6dbdSKonstantin Belousov 
67*03ca6dbdSKonstantin Belousov static bool
68*03ca6dbdSKonstantin Belousov ntsync_wait_all_prepare(struct ntsync_wait_state *state, bool *stop)
69*03ca6dbdSKonstantin Belousov {
70*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
71*03ca6dbdSKonstantin Belousov 	int alerti, i;
72*03ca6dbdSKonstantin Belousov 	bool first;
73*03ca6dbdSKonstantin Belousov 
74*03ca6dbdSKonstantin Belousov 	MPASS(state->all);
75*03ca6dbdSKonstantin Belousov 	MPASS(state->error == 0);
76*03ca6dbdSKonstantin Belousov 	MPASS(!*stop);
77*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(state->owner);
78*03ca6dbdSKonstantin Belousov 
79*03ca6dbdSKonstantin Belousov 	alerti = state->alert_event == NULL ? 0 : 1;
80*03ca6dbdSKonstantin Belousov 	first = true;
81*03ca6dbdSKonstantin Belousov 
82*03ca6dbdSKonstantin Belousov 	for (i = 0; i < state->obj_count - alerti; i++) {
83*03ca6dbdSKonstantin Belousov 		obj = state->objs[i];
84*03ca6dbdSKonstantin Belousov 		if (!obj->prepare(obj, state, i, stop))
85*03ca6dbdSKonstantin Belousov 			return (false);
86*03ca6dbdSKonstantin Belousov 		if (*stop) {
87*03ca6dbdSKonstantin Belousov 			MPASS(state->error != 0);
88*03ca6dbdSKonstantin Belousov 			return (false);
89*03ca6dbdSKonstantin Belousov 		}
90*03ca6dbdSKonstantin Belousov 		MPASS (state->error == 0);
91*03ca6dbdSKonstantin Belousov 		if (first) {
92*03ca6dbdSKonstantin Belousov 			first = false;
93*03ca6dbdSKonstantin Belousov 			state->index = i;
94*03ca6dbdSKonstantin Belousov 		}
95*03ca6dbdSKonstantin Belousov 	}
96*03ca6dbdSKonstantin Belousov 	return (true);
97*03ca6dbdSKonstantin Belousov }
98*03ca6dbdSKonstantin Belousov 
99*03ca6dbdSKonstantin Belousov static void
100*03ca6dbdSKonstantin Belousov ntsync_wait_all_commit(struct ntsync_wait_state *state)
101*03ca6dbdSKonstantin Belousov {
102*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
103*03ca6dbdSKonstantin Belousov 	int i, alerti;
104*03ca6dbdSKonstantin Belousov 
105*03ca6dbdSKonstantin Belousov 	MPASS(state->all);
106*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(state->owner);
107*03ca6dbdSKonstantin Belousov 	alerti = state->alert_event == NULL ? 0 : 1;
108*03ca6dbdSKonstantin Belousov 
109*03ca6dbdSKonstantin Belousov 	for (i = 0; i < state->obj_count - alerti; i++) {
110*03ca6dbdSKonstantin Belousov 		obj = state->objs[i];
111*03ca6dbdSKonstantin Belousov 		obj->commit(obj, state, i);
112*03ca6dbdSKonstantin Belousov 	}
113*03ca6dbdSKonstantin Belousov }
114*03ca6dbdSKonstantin Belousov 
115*03ca6dbdSKonstantin Belousov static void
116*03ca6dbdSKonstantin Belousov ntsync_wait_link_waiters(struct ntsync_wait_state *state)
117*03ca6dbdSKonstantin Belousov {
118*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
119*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_waiter *waiter;
120*03ca6dbdSKonstantin Belousov 	int i;
121*03ca6dbdSKonstantin Belousov 
122*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(state->owner);
123*03ca6dbdSKonstantin Belousov 
124*03ca6dbdSKonstantin Belousov 	for (i = 0; i < state->obj_count; i++) {
125*03ca6dbdSKonstantin Belousov 		obj = state->objs[i];
126*03ca6dbdSKonstantin Belousov 		waiter = &state->waiters[i];
127*03ca6dbdSKonstantin Belousov 		waiter->state = state;
128*03ca6dbdSKonstantin Belousov 		TAILQ_INSERT_TAIL(&obj->waiters, waiter, link);
129*03ca6dbdSKonstantin Belousov 	}
130*03ca6dbdSKonstantin Belousov }
131*03ca6dbdSKonstantin Belousov 
132*03ca6dbdSKonstantin Belousov static void
133*03ca6dbdSKonstantin Belousov ntsync_wait_unlink_waiters(struct ntsync_wait_state *state)
134*03ca6dbdSKonstantin Belousov {
135*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
136*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_waiter *waiter;
137*03ca6dbdSKonstantin Belousov 	int i;
138*03ca6dbdSKonstantin Belousov 
139*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(state->owner);
140*03ca6dbdSKonstantin Belousov 
141*03ca6dbdSKonstantin Belousov 	for (i = 0; i < state->obj_count; i++) {
142*03ca6dbdSKonstantin Belousov 		obj = state->objs[i];
143*03ca6dbdSKonstantin Belousov 		waiter = &state->waiters[i];
144*03ca6dbdSKonstantin Belousov 		TAILQ_REMOVE(&obj->waiters, waiter, link);
145*03ca6dbdSKonstantin Belousov 	}
146*03ca6dbdSKonstantin Belousov }
147*03ca6dbdSKonstantin Belousov 
148*03ca6dbdSKonstantin Belousov static void
149*03ca6dbdSKonstantin Belousov ntsync_wait_post_commit(struct ntsync_wait_state *state)
150*03ca6dbdSKonstantin Belousov {
151*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
152*03ca6dbdSKonstantin Belousov 	int alerti, i;
153*03ca6dbdSKonstantin Belousov 
154*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(state->owner);
155*03ca6dbdSKonstantin Belousov 
156*03ca6dbdSKonstantin Belousov 	alerti = state->alert_event == NULL ? 0 : 1;
157*03ca6dbdSKonstantin Belousov 	for (i = 0; i < state->obj_count - alerti; i++) {
158*03ca6dbdSKonstantin Belousov 		obj = state->objs[i];
159*03ca6dbdSKonstantin Belousov 		obj->post_commit(obj, state, i);
160*03ca6dbdSKonstantin Belousov 	}
161*03ca6dbdSKonstantin Belousov }
162*03ca6dbdSKonstantin Belousov 
163*03ca6dbdSKonstantin Belousov static void
164*03ca6dbdSKonstantin Belousov ntsync_wait_check_ready(struct ntsync_wait_state *state)
165*03ca6dbdSKonstantin Belousov {
166*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *ae;
167*03ca6dbdSKonstantin Belousov 	int index;
168*03ca6dbdSKonstantin Belousov 	bool stop;
169*03ca6dbdSKonstantin Belousov 
170*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(state->owner);
171*03ca6dbdSKonstantin Belousov 
172*03ca6dbdSKonstantin Belousov 	if (state->ready)
173*03ca6dbdSKonstantin Belousov 		return;
174*03ca6dbdSKonstantin Belousov 
175*03ca6dbdSKonstantin Belousov 	if (state->all) {
176*03ca6dbdSKonstantin Belousov 		stop = false;
177*03ca6dbdSKonstantin Belousov 		if (ntsync_wait_all_prepare(state, &stop)) {
178*03ca6dbdSKonstantin Belousov 			MPASS(!stop);
179*03ca6dbdSKonstantin Belousov 			ntsync_wait_all_commit(state);
180*03ca6dbdSKonstantin Belousov 			state->ready = true;
181*03ca6dbdSKonstantin Belousov 			ntsync_wait_post_commit(state);
182*03ca6dbdSKonstantin Belousov 		} else if (stop) {
183*03ca6dbdSKonstantin Belousov 			/* skip */
184*03ca6dbdSKonstantin Belousov 		} else if (state->alert_event != NULL) {
185*03ca6dbdSKonstantin Belousov 			ae = &state->alert_event->obj;
186*03ca6dbdSKonstantin Belousov 			index = state->obj_count - 1;
187*03ca6dbdSKonstantin Belousov 			if (ae->is_signaled(ae, state, index)) {
188*03ca6dbdSKonstantin Belousov 				state->index = index;
189*03ca6dbdSKonstantin Belousov 				ae->consume(ae, state, index);
190*03ca6dbdSKonstantin Belousov 				ae->post_commit(ae, state, index);
191*03ca6dbdSKonstantin Belousov 				state->ready = true;
192*03ca6dbdSKonstantin Belousov 			}
193*03ca6dbdSKonstantin Belousov 		}
194*03ca6dbdSKonstantin Belousov 	} else {	/* state->any */
195*03ca6dbdSKonstantin Belousov 		if (ntsync_wait_any(state))
196*03ca6dbdSKonstantin Belousov 			state->ready = true;
197*03ca6dbdSKonstantin Belousov 	}
198*03ca6dbdSKonstantin Belousov }
199*03ca6dbdSKonstantin Belousov 
200*03ca6dbdSKonstantin Belousov /*
201*03ca6dbdSKonstantin Belousov  * Perform the wait.  Errors returned through state->error still
202*03ca6dbdSKonstantin Belousov  * result in the copyout of the ntsync_wait_args after the wait, while
203*03ca6dbdSKonstantin Belousov  * errors returned as the function result do not.
204*03ca6dbdSKonstantin Belousov  */
205*03ca6dbdSKonstantin Belousov static int
206*03ca6dbdSKonstantin Belousov ntsync_wait_locked(struct ntsync_wait_state *state, struct thread *td)
207*03ca6dbdSKonstantin Belousov {
208*03ca6dbdSKonstantin Belousov 	int error;
209*03ca6dbdSKonstantin Belousov 
210*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(state->owner);
211*03ca6dbdSKonstantin Belousov 
212*03ca6dbdSKonstantin Belousov 	for (;;) {
213*03ca6dbdSKonstantin Belousov 		ntsync_wait_check_ready(state);
214*03ca6dbdSKonstantin Belousov 		if (state->ready)
215*03ca6dbdSKonstantin Belousov 			break;
216*03ca6dbdSKonstantin Belousov 		error = msleep_sbt(state, &state->owner->lock,
217*03ca6dbdSKonstantin Belousov 		    PCATCH, "ntsync", state->sb, 0,
218*03ca6dbdSKonstantin Belousov 		    C_ABSOLUTE /* | C_HARDCLOCK XXXKIB */);
219*03ca6dbdSKonstantin Belousov 
220*03ca6dbdSKonstantin Belousov 		/*
221*03ca6dbdSKonstantin Belousov 		 * Check state->ready before checking error from
222*03ca6dbdSKonstantin Belousov 		 * msleep().  If there was a wake up that set the
223*03ca6dbdSKonstantin Belousov 		 * readiness before us receiving a signal or timeout,
224*03ca6dbdSKonstantin Belousov 		 * the objects states are modified to reflect wakeup.
225*03ca6dbdSKonstantin Belousov 		 * Due to this, ready should result in normal return.
226*03ca6dbdSKonstantin Belousov 		 */
227*03ca6dbdSKonstantin Belousov 		if (state->ready) {
228*03ca6dbdSKonstantin Belousov 			error = 0;
229*03ca6dbdSKonstantin Belousov 			break;
230*03ca6dbdSKonstantin Belousov 		}
231*03ca6dbdSKonstantin Belousov 
232*03ca6dbdSKonstantin Belousov 		if (error != 0) {
233*03ca6dbdSKonstantin Belousov 			if (error == EAGAIN)
234*03ca6dbdSKonstantin Belousov 				error = ETIMEDOUT;
235*03ca6dbdSKonstantin Belousov 			break;
236*03ca6dbdSKonstantin Belousov 		}
237*03ca6dbdSKonstantin Belousov 	}
238*03ca6dbdSKonstantin Belousov 	return (error);
239*03ca6dbdSKonstantin Belousov }
240*03ca6dbdSKonstantin Belousov 
241*03ca6dbdSKonstantin Belousov static int
242*03ca6dbdSKonstantin Belousov ntsync_wait(struct ntsync_wait_state *state, struct thread *td)
243*03ca6dbdSKonstantin Belousov {
244*03ca6dbdSKonstantin Belousov 	int error;
245*03ca6dbdSKonstantin Belousov 
246*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_LOCK(state->owner);
247*03ca6dbdSKonstantin Belousov 	ntsync_wait_link_waiters(state);
248*03ca6dbdSKonstantin Belousov 	error = ntsync_wait_locked(state, td);
249*03ca6dbdSKonstantin Belousov 	ntsync_wait_unlink_waiters(state);
250*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_UNLOCK(state->owner);
251*03ca6dbdSKonstantin Belousov 	return (error);
252*03ca6dbdSKonstantin Belousov }
253*03ca6dbdSKonstantin Belousov 
254*03ca6dbdSKonstantin Belousov static void
255*03ca6dbdSKonstantin Belousov ntsync_wakeup_waiters(struct ntsync_obj *obj)
256*03ca6dbdSKonstantin Belousov {
257*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_waiter *w;
258*03ca6dbdSKonstantin Belousov 
259*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(obj->owner);
260*03ca6dbdSKonstantin Belousov 
261*03ca6dbdSKonstantin Belousov 	TAILQ_FOREACH(w, &obj->waiters, link) {
262*03ca6dbdSKonstantin Belousov 		ntsync_wait_check_ready(w->state);
263*03ca6dbdSKonstantin Belousov 		if (w->state->ready)
264*03ca6dbdSKonstantin Belousov 			wakeup(w->state);
265*03ca6dbdSKonstantin Belousov 	}
266*03ca6dbdSKonstantin Belousov }
267*03ca6dbdSKonstantin Belousov 
268*03ca6dbdSKonstantin Belousov static int
269*03ca6dbdSKonstantin Belousov ntsync_create_obj(struct ntsync_obj *obj, struct fileops *fops,
270*03ca6dbdSKonstantin Belousov     struct ntsync_priv *priv, struct thread *td)
271*03ca6dbdSKonstantin Belousov {
272*03ca6dbdSKonstantin Belousov 	struct file *fp;
273*03ca6dbdSKonstantin Belousov 	int error, fd;
274*03ca6dbdSKonstantin Belousov 
275*03ca6dbdSKonstantin Belousov 	error = falloc_noinstall(td, &fp);
276*03ca6dbdSKonstantin Belousov 	if (error != 0)
277*03ca6dbdSKonstantin Belousov 		return (error);
278*03ca6dbdSKonstantin Belousov 
279*03ca6dbdSKonstantin Belousov 	/*
280*03ca6dbdSKonstantin Belousov 	 * The priv fd cannot be closed during object creation since
281*03ca6dbdSKonstantin Belousov 	 * it is fget-ed around ioctl.
282*03ca6dbdSKonstantin Belousov 	 */
283*03ca6dbdSKonstantin Belousov 	obj->owner = priv;
284*03ca6dbdSKonstantin Belousov 
285*03ca6dbdSKonstantin Belousov 	TAILQ_INIT(&obj->waiters);
286*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_LOCK(priv);
287*03ca6dbdSKonstantin Belousov 	MPASS(!priv->closed);
288*03ca6dbdSKonstantin Belousov 	if (priv->objs_cnt == UINT_MAX) {
289*03ca6dbdSKonstantin Belousov 		NTSYNC_PRIV_UNLOCK(priv);
290*03ca6dbdSKonstantin Belousov 		fdrop(fp, td);
291*03ca6dbdSKonstantin Belousov 		return (EMFILE);
292*03ca6dbdSKonstantin Belousov 	}
293*03ca6dbdSKonstantin Belousov 	priv->objs_cnt++;
294*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_UNLOCK(priv);
295*03ca6dbdSKonstantin Belousov 
296*03ca6dbdSKonstantin Belousov 	finit(fp, FREAD | FWRITE, DTYPE_NTSYNC, obj, fops);
297*03ca6dbdSKonstantin Belousov 	error = finstall(td, fp, &fd, 0, NULL);
298*03ca6dbdSKonstantin Belousov 	if (error != 0) {
299*03ca6dbdSKonstantin Belousov 		NTSYNC_PRIV_LOCK(priv);
300*03ca6dbdSKonstantin Belousov 		MPASS(priv->objs_cnt > 0);
301*03ca6dbdSKonstantin Belousov 		priv->objs_cnt--;
302*03ca6dbdSKonstantin Belousov 		NTSYNC_PRIV_UNLOCK(priv);
303*03ca6dbdSKonstantin Belousov 	} else {
304*03ca6dbdSKonstantin Belousov 		td->td_retval[0] = fd;
305*03ca6dbdSKonstantin Belousov 	}
306*03ca6dbdSKonstantin Belousov 	fdrop(fp, td);
307*03ca6dbdSKonstantin Belousov 	return (error);
308*03ca6dbdSKonstantin Belousov }
309*03ca6dbdSKonstantin Belousov 
310*03ca6dbdSKonstantin Belousov static void
311*03ca6dbdSKonstantin Belousov ntsync_close_obj(struct ntsync_obj *obj, struct thread *td)
312*03ca6dbdSKonstantin Belousov {
313*03ca6dbdSKonstantin Belousov 	struct ntsync_priv *priv;
314*03ca6dbdSKonstantin Belousov 
315*03ca6dbdSKonstantin Belousov 	priv = obj->owner;
316*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_LOCK(priv);
317*03ca6dbdSKonstantin Belousov 	MPASS(priv->objs_cnt > 0);
318*03ca6dbdSKonstantin Belousov 	MPASS(TAILQ_EMPTY(&obj->waiters));
319*03ca6dbdSKonstantin Belousov 	priv->objs_cnt--;
320*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_UNLOCK(priv);
321*03ca6dbdSKonstantin Belousov 	ntsync_free_priv(priv);
322*03ca6dbdSKonstantin Belousov }
323*03ca6dbdSKonstantin Belousov 
324*03ca6dbdSKonstantin Belousov static bool
325*03ca6dbdSKonstantin Belousov ntsync_sem_is_signaled(struct ntsync_obj *obj, struct ntsync_wait_state *state,
326*03ca6dbdSKonstantin Belousov     int index)
327*03ca6dbdSKonstantin Belousov {
328*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_sem *sem;
329*03ca6dbdSKonstantin Belousov 
330*03ca6dbdSKonstantin Belousov 	MPASS(obj->type == NTSYNC_OBJ_SEM);
331*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(obj->owner);
332*03ca6dbdSKonstantin Belousov 	sem = OBJ_TO_SEM(obj);
333*03ca6dbdSKonstantin Belousov 	return (sem->a.count != 0);
334*03ca6dbdSKonstantin Belousov }
335*03ca6dbdSKonstantin Belousov 
336*03ca6dbdSKonstantin Belousov static void
337*03ca6dbdSKonstantin Belousov ntsync_sem_consume(struct ntsync_obj *obj, struct ntsync_wait_state *state,
338*03ca6dbdSKonstantin Belousov     int index)
339*03ca6dbdSKonstantin Belousov {
340*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_sem *sem;
341*03ca6dbdSKonstantin Belousov 
342*03ca6dbdSKonstantin Belousov 	MPASS(obj->type == NTSYNC_OBJ_SEM);
343*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(obj->owner);
344*03ca6dbdSKonstantin Belousov 	sem = OBJ_TO_SEM(obj);
345*03ca6dbdSKonstantin Belousov 	MPASS(sem->a.count != 0);
346*03ca6dbdSKonstantin Belousov 	sem->a.count--;
347*03ca6dbdSKonstantin Belousov }
348*03ca6dbdSKonstantin Belousov 
349*03ca6dbdSKonstantin Belousov static bool
350*03ca6dbdSKonstantin Belousov ntsync_sem_prepare(struct ntsync_obj *obj, struct ntsync_wait_state *state,
351*03ca6dbdSKonstantin Belousov     int index, bool *stop)
352*03ca6dbdSKonstantin Belousov {
353*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_sem *sem;
354*03ca6dbdSKonstantin Belousov 
355*03ca6dbdSKonstantin Belousov 	MPASS(obj->type == NTSYNC_OBJ_SEM);
356*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(obj->owner);
357*03ca6dbdSKonstantin Belousov 	sem = OBJ_TO_SEM(obj);
358*03ca6dbdSKonstantin Belousov 	if (sem->a.count == 0)
359*03ca6dbdSKonstantin Belousov 		return (false);
360*03ca6dbdSKonstantin Belousov 	sem->a1 = sem->a;
361*03ca6dbdSKonstantin Belousov 	sem->a1.count--;
362*03ca6dbdSKonstantin Belousov 	return (true);
363*03ca6dbdSKonstantin Belousov }
364*03ca6dbdSKonstantin Belousov 
365*03ca6dbdSKonstantin Belousov static void
366*03ca6dbdSKonstantin Belousov ntsync_sem_commit(struct ntsync_obj *obj, struct ntsync_wait_state *state,
367*03ca6dbdSKonstantin Belousov     int index)
368*03ca6dbdSKonstantin Belousov {
369*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_sem *sem;
370*03ca6dbdSKonstantin Belousov 
371*03ca6dbdSKonstantin Belousov 	MPASS(obj->type == NTSYNC_OBJ_SEM);
372*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(obj->owner);
373*03ca6dbdSKonstantin Belousov 	sem = OBJ_TO_SEM(obj);
374*03ca6dbdSKonstantin Belousov 	sem->a = sem->a1;
375*03ca6dbdSKonstantin Belousov }
376*03ca6dbdSKonstantin Belousov 
377*03ca6dbdSKonstantin Belousov static void
378*03ca6dbdSKonstantin Belousov ntsync_sem_post_commit(struct ntsync_obj *obj, struct ntsync_wait_state *state,
379*03ca6dbdSKonstantin Belousov     int index)
380*03ca6dbdSKonstantin Belousov {
381*03ca6dbdSKonstantin Belousov }
382*03ca6dbdSKonstantin Belousov 
383*03ca6dbdSKonstantin Belousov static int
384*03ca6dbdSKonstantin Belousov ntsync_sem_close(struct file *fp, struct thread *td)
385*03ca6dbdSKonstantin Belousov {
386*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_sem *sem;
387*03ca6dbdSKonstantin Belousov 
388*03ca6dbdSKonstantin Belousov 	sem = fp->f_data;
389*03ca6dbdSKonstantin Belousov 	ntsync_close_obj(&sem->obj, td);
390*03ca6dbdSKonstantin Belousov 	free(sem, M_NTSYNC);
391*03ca6dbdSKonstantin Belousov 	return (0);
392*03ca6dbdSKonstantin Belousov }
393*03ca6dbdSKonstantin Belousov 
394*03ca6dbdSKonstantin Belousov int
395*03ca6dbdSKonstantin Belousov ntsync_sem_release(struct thread *td, struct file *fp, uint32_t *val)
396*03ca6dbdSKonstantin Belousov {
397*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
398*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_sem *sem;
399*03ca6dbdSKonstantin Belousov 	struct ntsync_priv *priv;
400*03ca6dbdSKonstantin Belousov 	uint32_t prev;
401*03ca6dbdSKonstantin Belousov 	int error;
402*03ca6dbdSKonstantin Belousov 
403*03ca6dbdSKonstantin Belousov 	obj = fp->f_data;
404*03ca6dbdSKonstantin Belousov 	if (obj->type != NTSYNC_OBJ_SEM)
405*03ca6dbdSKonstantin Belousov 		return (EINVAL);
406*03ca6dbdSKonstantin Belousov 	sem = OBJ_TO_SEM(obj);
407*03ca6dbdSKonstantin Belousov 	priv = obj->owner;
408*03ca6dbdSKonstantin Belousov 	error = 0;
409*03ca6dbdSKonstantin Belousov 
410*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_LOCK(priv);
411*03ca6dbdSKonstantin Belousov 	if (sem->a.count + *val < sem->a.count ||
412*03ca6dbdSKonstantin Belousov 	    sem->a.count + *val > sem->a.max) {
413*03ca6dbdSKonstantin Belousov 		error = EOVERFLOW;
414*03ca6dbdSKonstantin Belousov 	} else {
415*03ca6dbdSKonstantin Belousov 		prev = sem->a.count;
416*03ca6dbdSKonstantin Belousov 		sem->a.count += *val;
417*03ca6dbdSKonstantin Belousov 		if (sem->a.count != 0)
418*03ca6dbdSKonstantin Belousov 			ntsync_wakeup_waiters(obj);
419*03ca6dbdSKonstantin Belousov 		*val = prev;
420*03ca6dbdSKonstantin Belousov 	}
421*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_UNLOCK(priv);
422*03ca6dbdSKonstantin Belousov 	return (error);
423*03ca6dbdSKonstantin Belousov }
424*03ca6dbdSKonstantin Belousov 
425*03ca6dbdSKonstantin Belousov int
426*03ca6dbdSKonstantin Belousov ntsync_sem_read(struct thread *td, struct file *fp, struct ntsync_sem_args *a)
427*03ca6dbdSKonstantin Belousov {
428*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
429*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_sem *sem;
430*03ca6dbdSKonstantin Belousov 	struct ntsync_priv *priv;
431*03ca6dbdSKonstantin Belousov 
432*03ca6dbdSKonstantin Belousov 	obj = fp->f_data;
433*03ca6dbdSKonstantin Belousov 	if (obj->type != NTSYNC_OBJ_SEM)
434*03ca6dbdSKonstantin Belousov 		return (EINVAL);
435*03ca6dbdSKonstantin Belousov 	sem = OBJ_TO_SEM(obj);
436*03ca6dbdSKonstantin Belousov 	priv = obj->owner;
437*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_LOCK(priv);
438*03ca6dbdSKonstantin Belousov 	*a = sem->a;
439*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_UNLOCK(priv);
440*03ca6dbdSKonstantin Belousov 	return (0);
441*03ca6dbdSKonstantin Belousov }
442*03ca6dbdSKonstantin Belousov 
443*03ca6dbdSKonstantin Belousov static int
444*03ca6dbdSKonstantin Belousov ntsync_sem_ioctl(struct file *fp, u_long com, void *data,
445*03ca6dbdSKonstantin Belousov     struct ucred *active_cred, struct thread *td)
446*03ca6dbdSKonstantin Belousov {
447*03ca6dbdSKonstantin Belousov 	int error;
448*03ca6dbdSKonstantin Belousov 
449*03ca6dbdSKonstantin Belousov 	switch (com) {
450*03ca6dbdSKonstantin Belousov 	case NTSYNC_IOC_SEM_RELEASE:
451*03ca6dbdSKonstantin Belousov 		error = ntsync_sem_release(td, fp, data);
452*03ca6dbdSKonstantin Belousov 		break;
453*03ca6dbdSKonstantin Belousov 	case NTSYNC_IOC_SEM_READ:
454*03ca6dbdSKonstantin Belousov 		error = ntsync_sem_read(td, fp, data);
455*03ca6dbdSKonstantin Belousov 		break;
456*03ca6dbdSKonstantin Belousov 	default:
457*03ca6dbdSKonstantin Belousov 		error = ENOTTY;
458*03ca6dbdSKonstantin Belousov 		break;
459*03ca6dbdSKonstantin Belousov 	}
460*03ca6dbdSKonstantin Belousov 	return (error);
461*03ca6dbdSKonstantin Belousov }
462*03ca6dbdSKonstantin Belousov 
463*03ca6dbdSKonstantin Belousov static int
464*03ca6dbdSKonstantin Belousov ntsync_sem_stat(struct file *fp, struct stat *sbp, struct ucred *cred)
465*03ca6dbdSKonstantin Belousov {
466*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
467*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_sem *sem;
468*03ca6dbdSKonstantin Belousov 
469*03ca6dbdSKonstantin Belousov 	MPASS(fp->f_type == DTYPE_NTSYNC);
470*03ca6dbdSKonstantin Belousov 	obj = fp->f_data;
471*03ca6dbdSKonstantin Belousov 	MPASS(obj->type == NTSYNC_OBJ_SEM);
472*03ca6dbdSKonstantin Belousov 	sem = OBJ_TO_SEM(obj);
473*03ca6dbdSKonstantin Belousov 
474*03ca6dbdSKonstantin Belousov 	memset(sbp, 0, sizeof(*sbp));
475*03ca6dbdSKonstantin Belousov 	sbp->st_mode = S_IFREG /* XXXKIB */ | S_IRUSR | S_IWUSR;
476*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_LOCK(obj->owner);
477*03ca6dbdSKonstantin Belousov 	sbp->st_size = sem->a.max;
478*03ca6dbdSKonstantin Belousov 	sbp->st_nlink = sem->a.count;
479*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_UNLOCK(obj->owner);
480*03ca6dbdSKonstantin Belousov 	return (0);
481*03ca6dbdSKonstantin Belousov }
482*03ca6dbdSKonstantin Belousov 
483*03ca6dbdSKonstantin Belousov static int
484*03ca6dbdSKonstantin Belousov ntsync_sem_fill_kinfo(struct file *fp, struct kinfo_file *kif,
485*03ca6dbdSKonstantin Belousov     struct filedesc *fdp)
486*03ca6dbdSKonstantin Belousov {
487*03ca6dbdSKonstantin Belousov 	// XXXKIB
488*03ca6dbdSKonstantin Belousov 	return (0);
489*03ca6dbdSKonstantin Belousov }
490*03ca6dbdSKonstantin Belousov 
491*03ca6dbdSKonstantin Belousov struct fileops ntsync_sem_fops = {
492*03ca6dbdSKonstantin Belousov 	.fo_read = invfo_rdwr,
493*03ca6dbdSKonstantin Belousov 	.fo_write = invfo_rdwr,
494*03ca6dbdSKonstantin Belousov 	.fo_truncate = invfo_truncate,
495*03ca6dbdSKonstantin Belousov 	.fo_ioctl = ntsync_sem_ioctl,
496*03ca6dbdSKonstantin Belousov 	.fo_poll = invfo_poll,
497*03ca6dbdSKonstantin Belousov 	.fo_kqfilter = invfo_kqfilter,
498*03ca6dbdSKonstantin Belousov 	.fo_stat = ntsync_sem_stat,
499*03ca6dbdSKonstantin Belousov 	.fo_close = ntsync_sem_close,
500*03ca6dbdSKonstantin Belousov 	.fo_chmod = invfo_chmod,
501*03ca6dbdSKonstantin Belousov 	.fo_chown = invfo_chown,
502*03ca6dbdSKonstantin Belousov 	.fo_sendfile = invfo_sendfile,
503*03ca6dbdSKonstantin Belousov 	.fo_fill_kinfo = ntsync_sem_fill_kinfo,
504*03ca6dbdSKonstantin Belousov 	.fo_flags = DFLAG_PASSABLE,
505*03ca6dbdSKonstantin Belousov };
506*03ca6dbdSKonstantin Belousov 
507*03ca6dbdSKonstantin Belousov static int
508*03ca6dbdSKonstantin Belousov ntsync_create_sem(struct ntsync_sem_args *args, struct ntsync_priv *priv,
509*03ca6dbdSKonstantin Belousov     struct thread *td)
510*03ca6dbdSKonstantin Belousov {
511*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_sem *sem;
512*03ca6dbdSKonstantin Belousov 	int error;
513*03ca6dbdSKonstantin Belousov 
514*03ca6dbdSKonstantin Belousov 	if (args->count > args->max)
515*03ca6dbdSKonstantin Belousov 		return (EINVAL);
516*03ca6dbdSKonstantin Belousov 
517*03ca6dbdSKonstantin Belousov 	sem = malloc(sizeof(*sem), M_NTSYNC, M_WAITOK | M_ZERO);
518*03ca6dbdSKonstantin Belousov 	sem->obj.type = NTSYNC_OBJ_SEM;
519*03ca6dbdSKonstantin Belousov 	sem->obj.is_signaled = ntsync_sem_is_signaled;
520*03ca6dbdSKonstantin Belousov 	sem->obj.consume = ntsync_sem_consume;
521*03ca6dbdSKonstantin Belousov 	sem->obj.prepare = ntsync_sem_prepare;
522*03ca6dbdSKonstantin Belousov 	sem->obj.commit = ntsync_sem_commit;
523*03ca6dbdSKonstantin Belousov 	sem->obj.post_commit = ntsync_sem_post_commit;
524*03ca6dbdSKonstantin Belousov 	sem->a = *args;
525*03ca6dbdSKonstantin Belousov 
526*03ca6dbdSKonstantin Belousov 	error = ntsync_create_obj(&sem->obj, &ntsync_sem_fops, priv, td);
527*03ca6dbdSKonstantin Belousov 	if (error != 0)
528*03ca6dbdSKonstantin Belousov 		free(sem, M_NTSYNC);
529*03ca6dbdSKonstantin Belousov 
530*03ca6dbdSKonstantin Belousov 	return (error);
531*03ca6dbdSKonstantin Belousov }
532*03ca6dbdSKonstantin Belousov 
533*03ca6dbdSKonstantin Belousov static bool
534*03ca6dbdSKonstantin Belousov ntsync_mutex_can_lock(struct ntsync_obj_mutex *mutex, uint32_t nwa_owner)
535*03ca6dbdSKonstantin Belousov {
536*03ca6dbdSKonstantin Belousov 	return (mutex->a.owner == 0 ||
537*03ca6dbdSKonstantin Belousov 	    (mutex->a.owner == nwa_owner && mutex->a.count < UINT32_MAX) ||
538*03ca6dbdSKonstantin Belousov 	    mutex->abandoned);
539*03ca6dbdSKonstantin Belousov }
540*03ca6dbdSKonstantin Belousov 
541*03ca6dbdSKonstantin Belousov static bool
542*03ca6dbdSKonstantin Belousov ntsync_mutex_is_signaled(struct ntsync_obj *obj,
543*03ca6dbdSKonstantin Belousov     struct ntsync_wait_state *state, int index)
544*03ca6dbdSKonstantin Belousov {
545*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_mutex *mutex;
546*03ca6dbdSKonstantin Belousov 
547*03ca6dbdSKonstantin Belousov 	MPASS(obj->type == NTSYNC_OBJ_MUTEX);
548*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(obj->owner);
549*03ca6dbdSKonstantin Belousov 	mutex = OBJ_TO_MUTEX(obj);
550*03ca6dbdSKonstantin Belousov 	return (ntsync_mutex_can_lock(mutex, state->nwa->owner));
551*03ca6dbdSKonstantin Belousov }
552*03ca6dbdSKonstantin Belousov 
553*03ca6dbdSKonstantin Belousov static void
554*03ca6dbdSKonstantin Belousov ntsync_mutex_consume(struct ntsync_obj *obj, struct ntsync_wait_state *state,
555*03ca6dbdSKonstantin Belousov     int index)
556*03ca6dbdSKonstantin Belousov {
557*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_mutex *mutex;
558*03ca6dbdSKonstantin Belousov 
559*03ca6dbdSKonstantin Belousov 	MPASS(obj->type == NTSYNC_OBJ_MUTEX);
560*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(obj->owner);
561*03ca6dbdSKonstantin Belousov 	mutex = OBJ_TO_MUTEX(obj);
562*03ca6dbdSKonstantin Belousov 	MPASS(ntsync_mutex_can_lock(mutex, state->nwa->owner));
563*03ca6dbdSKonstantin Belousov 	if (state->nwa->owner == 0) {
564*03ca6dbdSKonstantin Belousov 		state->error = EINVAL;
565*03ca6dbdSKonstantin Belousov 		return;
566*03ca6dbdSKonstantin Belousov 	}
567*03ca6dbdSKonstantin Belousov 	if (mutex->a.owner == 0 || mutex->abandoned)
568*03ca6dbdSKonstantin Belousov 		mutex->a.count = 1;
569*03ca6dbdSKonstantin Belousov 	else
570*03ca6dbdSKonstantin Belousov 		mutex->a.count++;
571*03ca6dbdSKonstantin Belousov 	mutex->a.owner = state->nwa->owner;
572*03ca6dbdSKonstantin Belousov 	if (mutex->abandoned && state->error == 0)
573*03ca6dbdSKonstantin Belousov 		state->error = EOWNERDEAD;
574*03ca6dbdSKonstantin Belousov 	mutex->abandoned = false;
575*03ca6dbdSKonstantin Belousov }
576*03ca6dbdSKonstantin Belousov 
577*03ca6dbdSKonstantin Belousov static bool
578*03ca6dbdSKonstantin Belousov ntsync_mutex_prepare(struct ntsync_obj *obj, struct ntsync_wait_state *state,
579*03ca6dbdSKonstantin Belousov     int index, bool *stop)
580*03ca6dbdSKonstantin Belousov {
581*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_mutex *mutex;
582*03ca6dbdSKonstantin Belousov 
583*03ca6dbdSKonstantin Belousov 	MPASS(obj->type == NTSYNC_OBJ_MUTEX);
584*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(obj->owner);
585*03ca6dbdSKonstantin Belousov 	mutex = OBJ_TO_MUTEX(obj);
586*03ca6dbdSKonstantin Belousov 	if (!ntsync_mutex_can_lock(mutex, state->nwa->owner))
587*03ca6dbdSKonstantin Belousov 		return (false);
588*03ca6dbdSKonstantin Belousov 	if (state->nwa->owner == 0) {
589*03ca6dbdSKonstantin Belousov 		state->error = EINVAL;
590*03ca6dbdSKonstantin Belousov 		*stop = true;
591*03ca6dbdSKonstantin Belousov 		return (false);
592*03ca6dbdSKonstantin Belousov 	}
593*03ca6dbdSKonstantin Belousov 	mutex->a1 = mutex->a;
594*03ca6dbdSKonstantin Belousov 	if (mutex->a.owner == 0 || mutex->abandoned)
595*03ca6dbdSKonstantin Belousov 		mutex->a1.count = 1;
596*03ca6dbdSKonstantin Belousov 	else
597*03ca6dbdSKonstantin Belousov 		mutex->a1.count++;
598*03ca6dbdSKonstantin Belousov 	mutex->a1.owner = state->nwa->owner;
599*03ca6dbdSKonstantin Belousov 	return (true);
600*03ca6dbdSKonstantin Belousov }
601*03ca6dbdSKonstantin Belousov 
602*03ca6dbdSKonstantin Belousov static void
603*03ca6dbdSKonstantin Belousov ntsync_mutex_commit(struct ntsync_obj *obj, struct ntsync_wait_state *state,
604*03ca6dbdSKonstantin Belousov     int index)
605*03ca6dbdSKonstantin Belousov {
606*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_mutex *mutex;
607*03ca6dbdSKonstantin Belousov 
608*03ca6dbdSKonstantin Belousov 	MPASS(obj->type == NTSYNC_OBJ_MUTEX);
609*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(obj->owner);
610*03ca6dbdSKonstantin Belousov 	mutex = OBJ_TO_MUTEX(obj);
611*03ca6dbdSKonstantin Belousov 	mutex->a = mutex->a1;
612*03ca6dbdSKonstantin Belousov 	if (mutex->abandoned)
613*03ca6dbdSKonstantin Belousov 		state->error = EOWNERDEAD;
614*03ca6dbdSKonstantin Belousov 	mutex->abandoned = false;
615*03ca6dbdSKonstantin Belousov }
616*03ca6dbdSKonstantin Belousov 
617*03ca6dbdSKonstantin Belousov static void
618*03ca6dbdSKonstantin Belousov ntsync_mutex_post_commit(struct ntsync_obj *obj,
619*03ca6dbdSKonstantin Belousov     struct ntsync_wait_state *state, int index)
620*03ca6dbdSKonstantin Belousov {
621*03ca6dbdSKonstantin Belousov }
622*03ca6dbdSKonstantin Belousov 
623*03ca6dbdSKonstantin Belousov static int
624*03ca6dbdSKonstantin Belousov ntsync_mutex_close(struct file *fp, struct thread *td)
625*03ca6dbdSKonstantin Belousov {
626*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_mutex *mutex;
627*03ca6dbdSKonstantin Belousov 
628*03ca6dbdSKonstantin Belousov 	mutex = fp->f_data;
629*03ca6dbdSKonstantin Belousov 	ntsync_close_obj(&mutex->obj, td);
630*03ca6dbdSKonstantin Belousov 	free(mutex, M_NTSYNC);
631*03ca6dbdSKonstantin Belousov 	return (0);
632*03ca6dbdSKonstantin Belousov }
633*03ca6dbdSKonstantin Belousov 
634*03ca6dbdSKonstantin Belousov int
635*03ca6dbdSKonstantin Belousov ntsync_mutex_unlock(struct thread *td, struct file *fp,
636*03ca6dbdSKonstantin Belousov     struct ntsync_mutex_args *a)
637*03ca6dbdSKonstantin Belousov {
638*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
639*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_mutex *mutex;
640*03ca6dbdSKonstantin Belousov 	struct ntsync_priv *priv;
641*03ca6dbdSKonstantin Belousov 	uint32_t prev;
642*03ca6dbdSKonstantin Belousov 	int error;
643*03ca6dbdSKonstantin Belousov 
644*03ca6dbdSKonstantin Belousov 	obj = fp->f_data;
645*03ca6dbdSKonstantin Belousov 	if (obj->type != NTSYNC_OBJ_MUTEX)
646*03ca6dbdSKonstantin Belousov 		return (EINVAL);
647*03ca6dbdSKonstantin Belousov 	mutex = OBJ_TO_MUTEX(obj);
648*03ca6dbdSKonstantin Belousov 	priv = obj->owner;
649*03ca6dbdSKonstantin Belousov 
650*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_LOCK(priv);
651*03ca6dbdSKonstantin Belousov 	if (a->owner == 0) {
652*03ca6dbdSKonstantin Belousov 		error = EINVAL;
653*03ca6dbdSKonstantin Belousov 	} else if (a->owner != mutex->a.owner) {
654*03ca6dbdSKonstantin Belousov 		error = EPERM;
655*03ca6dbdSKonstantin Belousov 	} else {
656*03ca6dbdSKonstantin Belousov 		error = 0;
657*03ca6dbdSKonstantin Belousov 		prev = mutex->a.count;
658*03ca6dbdSKonstantin Belousov 		MPASS(mutex->a.count > 0);
659*03ca6dbdSKonstantin Belousov 		mutex->a.count--;
660*03ca6dbdSKonstantin Belousov 		a->count = prev;
661*03ca6dbdSKonstantin Belousov 		if (mutex->a.count == 0) {
662*03ca6dbdSKonstantin Belousov 			mutex->a.owner = 0;
663*03ca6dbdSKonstantin Belousov 			ntsync_wakeup_waiters(obj);
664*03ca6dbdSKonstantin Belousov 		}
665*03ca6dbdSKonstantin Belousov 	}
666*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_UNLOCK(priv);
667*03ca6dbdSKonstantin Belousov 	return (error);
668*03ca6dbdSKonstantin Belousov }
669*03ca6dbdSKonstantin Belousov 
670*03ca6dbdSKonstantin Belousov int
671*03ca6dbdSKonstantin Belousov ntsync_mutex_kill(struct thread *td, struct file *fp, uint32_t val)
672*03ca6dbdSKonstantin Belousov {
673*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
674*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_mutex *mutex;
675*03ca6dbdSKonstantin Belousov 	struct ntsync_priv *priv;
676*03ca6dbdSKonstantin Belousov 	int error;
677*03ca6dbdSKonstantin Belousov 
678*03ca6dbdSKonstantin Belousov 	obj = fp->f_data;
679*03ca6dbdSKonstantin Belousov 	if (obj->type != NTSYNC_OBJ_MUTEX)
680*03ca6dbdSKonstantin Belousov 		return (EINVAL);
681*03ca6dbdSKonstantin Belousov 	mutex = OBJ_TO_MUTEX(obj);
682*03ca6dbdSKonstantin Belousov 	priv = obj->owner;
683*03ca6dbdSKonstantin Belousov 
684*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_LOCK(priv);
685*03ca6dbdSKonstantin Belousov 	if (val == 0) {
686*03ca6dbdSKonstantin Belousov 		error = EINVAL;
687*03ca6dbdSKonstantin Belousov 	} else if (mutex->a.owner != val) {
688*03ca6dbdSKonstantin Belousov 		error = EPERM;
689*03ca6dbdSKonstantin Belousov 	} else {
690*03ca6dbdSKonstantin Belousov 		error = 0;
691*03ca6dbdSKonstantin Belousov 		mutex->a.owner = 0;
692*03ca6dbdSKonstantin Belousov 		mutex->a.count = 0;
693*03ca6dbdSKonstantin Belousov 		mutex->abandoned = true;
694*03ca6dbdSKonstantin Belousov 		ntsync_wakeup_waiters(obj);
695*03ca6dbdSKonstantin Belousov 	}
696*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_UNLOCK(priv);
697*03ca6dbdSKonstantin Belousov 	return (error);
698*03ca6dbdSKonstantin Belousov }
699*03ca6dbdSKonstantin Belousov 
700*03ca6dbdSKonstantin Belousov int
701*03ca6dbdSKonstantin Belousov ntsync_mutex_read(struct thread *td, struct file *fp,
702*03ca6dbdSKonstantin Belousov     struct ntsync_mutex_args *a, bool *doco)
703*03ca6dbdSKonstantin Belousov {
704*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
705*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_mutex *mutex;
706*03ca6dbdSKonstantin Belousov 	struct ntsync_priv *priv;
707*03ca6dbdSKonstantin Belousov 	int error;
708*03ca6dbdSKonstantin Belousov 
709*03ca6dbdSKonstantin Belousov 	*doco = false;
710*03ca6dbdSKonstantin Belousov 	obj = fp->f_data;
711*03ca6dbdSKonstantin Belousov 	if (obj->type != NTSYNC_OBJ_MUTEX)
712*03ca6dbdSKonstantin Belousov 		return (EINVAL);
713*03ca6dbdSKonstantin Belousov 	mutex = OBJ_TO_MUTEX(obj);
714*03ca6dbdSKonstantin Belousov 	priv = obj->owner;
715*03ca6dbdSKonstantin Belousov 	error = 0;
716*03ca6dbdSKonstantin Belousov 
717*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_LOCK(priv);
718*03ca6dbdSKonstantin Belousov 	*a = mutex->a;
719*03ca6dbdSKonstantin Belousov 	if (mutex->abandoned)
720*03ca6dbdSKonstantin Belousov 		error = EOWNERDEAD;
721*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_UNLOCK(priv);
722*03ca6dbdSKonstantin Belousov 	*doco = true;
723*03ca6dbdSKonstantin Belousov 	return (error);
724*03ca6dbdSKonstantin Belousov }
725*03ca6dbdSKonstantin Belousov 
726*03ca6dbdSKonstantin Belousov static int
727*03ca6dbdSKonstantin Belousov ntsync_mutex_ioctl(struct file *fp, u_long com, void *data,
728*03ca6dbdSKonstantin Belousov     struct ucred *active_cred, struct thread *td)
729*03ca6dbdSKonstantin Belousov {
730*03ca6dbdSKonstantin Belousov 	struct ntsync_mutex_args aa;
731*03ca6dbdSKonstantin Belousov 	int error, error1;
732*03ca6dbdSKonstantin Belousov 	bool doco;
733*03ca6dbdSKonstantin Belousov 
734*03ca6dbdSKonstantin Belousov 	doco = false;
735*03ca6dbdSKonstantin Belousov 	switch (com) {
736*03ca6dbdSKonstantin Belousov 	case NTSYNC_IOC_MUTEX_UNLOCK:
737*03ca6dbdSKonstantin Belousov 		error = ntsync_mutex_unlock(td, fp, data);
738*03ca6dbdSKonstantin Belousov 		break;
739*03ca6dbdSKonstantin Belousov 	case NTSYNC_IOC_MUTEX_KILL:
740*03ca6dbdSKonstantin Belousov 		error = ntsync_mutex_kill(td, fp, *(uint32_t *)data);
741*03ca6dbdSKonstantin Belousov 		break;
742*03ca6dbdSKonstantin Belousov 	case NTSYNC_IOC_MUTEX_READ:
743*03ca6dbdSKonstantin Belousov 		error = ntsync_mutex_read(td, fp, &aa, &doco);
744*03ca6dbdSKonstantin Belousov 		if (doco) {
745*03ca6dbdSKonstantin Belousov 			error1 = ntsync_ioctl_copyout(td, &aa, sizeof(aa));
746*03ca6dbdSKonstantin Belousov 			if (error1 != 0)
747*03ca6dbdSKonstantin Belousov 				error = error1;
748*03ca6dbdSKonstantin Belousov 		}
749*03ca6dbdSKonstantin Belousov 		break;
750*03ca6dbdSKonstantin Belousov 	default:
751*03ca6dbdSKonstantin Belousov 		error = ENOTTY;
752*03ca6dbdSKonstantin Belousov 		break;
753*03ca6dbdSKonstantin Belousov 	}
754*03ca6dbdSKonstantin Belousov 	return (error);
755*03ca6dbdSKonstantin Belousov }
756*03ca6dbdSKonstantin Belousov 
757*03ca6dbdSKonstantin Belousov static int
758*03ca6dbdSKonstantin Belousov ntsync_mutex_stat(struct file *fp, struct stat *sbp, struct ucred *cred)
759*03ca6dbdSKonstantin Belousov {
760*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
761*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_mutex *mutex;
762*03ca6dbdSKonstantin Belousov 
763*03ca6dbdSKonstantin Belousov 	MPASS(fp->f_type == DTYPE_NTSYNC);
764*03ca6dbdSKonstantin Belousov 	obj = fp->f_data;
765*03ca6dbdSKonstantin Belousov 	MPASS(obj->type == NTSYNC_OBJ_MUTEX);
766*03ca6dbdSKonstantin Belousov 	mutex = OBJ_TO_MUTEX(obj);
767*03ca6dbdSKonstantin Belousov 
768*03ca6dbdSKonstantin Belousov 	memset(sbp, 0, sizeof(*sbp));
769*03ca6dbdSKonstantin Belousov 	sbp->st_mode = S_IFREG /* XXXKIB */ | S_IRUSR | S_IWUSR;
770*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_LOCK(obj->owner);
771*03ca6dbdSKonstantin Belousov 	sbp->st_size = mutex->a.owner;
772*03ca6dbdSKonstantin Belousov 	sbp->st_nlink = mutex->a.count;
773*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_UNLOCK(obj->owner);
774*03ca6dbdSKonstantin Belousov 	return (0);
775*03ca6dbdSKonstantin Belousov }
776*03ca6dbdSKonstantin Belousov 
777*03ca6dbdSKonstantin Belousov static int
778*03ca6dbdSKonstantin Belousov ntsync_mutex_fill_kinfo(struct file *fp, struct kinfo_file *kif,
779*03ca6dbdSKonstantin Belousov     struct filedesc *fdp)
780*03ca6dbdSKonstantin Belousov {
781*03ca6dbdSKonstantin Belousov 	// XXXKIB
782*03ca6dbdSKonstantin Belousov 	return (0);
783*03ca6dbdSKonstantin Belousov }
784*03ca6dbdSKonstantin Belousov 
785*03ca6dbdSKonstantin Belousov struct fileops ntsync_mutex_fops = {
786*03ca6dbdSKonstantin Belousov 	.fo_read = invfo_rdwr,
787*03ca6dbdSKonstantin Belousov 	.fo_write = invfo_rdwr,
788*03ca6dbdSKonstantin Belousov 	.fo_truncate = invfo_truncate,
789*03ca6dbdSKonstantin Belousov 	.fo_ioctl = ntsync_mutex_ioctl,
790*03ca6dbdSKonstantin Belousov 	.fo_poll = invfo_poll,
791*03ca6dbdSKonstantin Belousov 	.fo_kqfilter = invfo_kqfilter,
792*03ca6dbdSKonstantin Belousov 	.fo_stat = ntsync_mutex_stat,
793*03ca6dbdSKonstantin Belousov 	.fo_close = ntsync_mutex_close,
794*03ca6dbdSKonstantin Belousov 	.fo_chmod = invfo_chmod,
795*03ca6dbdSKonstantin Belousov 	.fo_chown = invfo_chown,
796*03ca6dbdSKonstantin Belousov 	.fo_sendfile = invfo_sendfile,
797*03ca6dbdSKonstantin Belousov 	.fo_fill_kinfo = ntsync_mutex_fill_kinfo,
798*03ca6dbdSKonstantin Belousov 	.fo_flags = DFLAG_PASSABLE,
799*03ca6dbdSKonstantin Belousov };
800*03ca6dbdSKonstantin Belousov 
801*03ca6dbdSKonstantin Belousov static int
802*03ca6dbdSKonstantin Belousov ntsync_create_mutex(struct ntsync_mutex_args *args, struct ntsync_priv *priv,
803*03ca6dbdSKonstantin Belousov     struct thread *td)
804*03ca6dbdSKonstantin Belousov {
805*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_mutex *mutex;
806*03ca6dbdSKonstantin Belousov 	int error;
807*03ca6dbdSKonstantin Belousov 
808*03ca6dbdSKonstantin Belousov 	if ((args->owner != 0 && args->count == 0) ||
809*03ca6dbdSKonstantin Belousov 	    (args->owner == 0 && args->count != 0))
810*03ca6dbdSKonstantin Belousov 		return (EINVAL);
811*03ca6dbdSKonstantin Belousov 
812*03ca6dbdSKonstantin Belousov 	mutex = malloc(sizeof(*mutex), M_NTSYNC, M_WAITOK | M_ZERO);
813*03ca6dbdSKonstantin Belousov 	mutex->obj.type = NTSYNC_OBJ_MUTEX;
814*03ca6dbdSKonstantin Belousov 	mutex->obj.is_signaled = ntsync_mutex_is_signaled;
815*03ca6dbdSKonstantin Belousov 	mutex->obj.consume = ntsync_mutex_consume;
816*03ca6dbdSKonstantin Belousov 	mutex->obj.prepare = ntsync_mutex_prepare;
817*03ca6dbdSKonstantin Belousov 	mutex->obj.commit = ntsync_mutex_commit;
818*03ca6dbdSKonstantin Belousov 	mutex->obj.post_commit = ntsync_mutex_post_commit;
819*03ca6dbdSKonstantin Belousov 	mutex->a = *args;
820*03ca6dbdSKonstantin Belousov 	mutex->abandoned = false;
821*03ca6dbdSKonstantin Belousov 
822*03ca6dbdSKonstantin Belousov 	error = ntsync_create_obj(&mutex->obj, &ntsync_mutex_fops, priv, td);
823*03ca6dbdSKonstantin Belousov 	if (error != 0)
824*03ca6dbdSKonstantin Belousov 		free(mutex, M_NTSYNC);
825*03ca6dbdSKonstantin Belousov 
826*03ca6dbdSKonstantin Belousov 	return (error);
827*03ca6dbdSKonstantin Belousov }
828*03ca6dbdSKonstantin Belousov 
829*03ca6dbdSKonstantin Belousov static bool
830*03ca6dbdSKonstantin Belousov ntsync_event_is_signaled(struct ntsync_obj *obj,
831*03ca6dbdSKonstantin Belousov     struct ntsync_wait_state *state, int index)
832*03ca6dbdSKonstantin Belousov {
833*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_event *event;
834*03ca6dbdSKonstantin Belousov 
835*03ca6dbdSKonstantin Belousov 	MPASS(obj->type == NTSYNC_OBJ_EVENT);
836*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(obj->owner);
837*03ca6dbdSKonstantin Belousov 	event = OBJ_TO_EVENT(obj);
838*03ca6dbdSKonstantin Belousov 	return (event->a.signaled != 0);
839*03ca6dbdSKonstantin Belousov }
840*03ca6dbdSKonstantin Belousov 
841*03ca6dbdSKonstantin Belousov static void
842*03ca6dbdSKonstantin Belousov ntsync_event_consume(struct ntsync_obj *obj, struct ntsync_wait_state *state,
843*03ca6dbdSKonstantin Belousov     int index)
844*03ca6dbdSKonstantin Belousov {
845*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_event *event;
846*03ca6dbdSKonstantin Belousov 
847*03ca6dbdSKonstantin Belousov 	MPASS(obj->type == NTSYNC_OBJ_EVENT);
848*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(obj->owner);
849*03ca6dbdSKonstantin Belousov 	MPASS(ntsync_event_is_signaled(obj, state, index));
850*03ca6dbdSKonstantin Belousov 
851*03ca6dbdSKonstantin Belousov 	event = OBJ_TO_EVENT(obj);
852*03ca6dbdSKonstantin Belousov 	if (event->a.manual == 0)
853*03ca6dbdSKonstantin Belousov 		event->a.signaled = 0;
854*03ca6dbdSKonstantin Belousov }
855*03ca6dbdSKonstantin Belousov 
856*03ca6dbdSKonstantin Belousov static bool
857*03ca6dbdSKonstantin Belousov ntsync_event_prepare(struct ntsync_obj *obj, struct ntsync_wait_state *state,
858*03ca6dbdSKonstantin Belousov     int index, bool *stop)
859*03ca6dbdSKonstantin Belousov {
860*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_event *event;
861*03ca6dbdSKonstantin Belousov 
862*03ca6dbdSKonstantin Belousov 	MPASS(obj->type == NTSYNC_OBJ_EVENT);
863*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(obj->owner);
864*03ca6dbdSKonstantin Belousov 	event = OBJ_TO_EVENT(obj);
865*03ca6dbdSKonstantin Belousov 	if (!ntsync_event_is_signaled(obj, state, index))
866*03ca6dbdSKonstantin Belousov 		return (false);
867*03ca6dbdSKonstantin Belousov 	event->a1 = event->a;
868*03ca6dbdSKonstantin Belousov 	return (true);
869*03ca6dbdSKonstantin Belousov }
870*03ca6dbdSKonstantin Belousov 
871*03ca6dbdSKonstantin Belousov static void
872*03ca6dbdSKonstantin Belousov ntsync_event_commit(struct ntsync_obj *obj, struct ntsync_wait_state *state,
873*03ca6dbdSKonstantin Belousov     int index)
874*03ca6dbdSKonstantin Belousov {
875*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_event *event;
876*03ca6dbdSKonstantin Belousov 
877*03ca6dbdSKonstantin Belousov 	MPASS(obj->type == NTSYNC_OBJ_EVENT);
878*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(obj->owner);
879*03ca6dbdSKonstantin Belousov 	event = OBJ_TO_EVENT(obj);
880*03ca6dbdSKonstantin Belousov 	event->a = event->a1;
881*03ca6dbdSKonstantin Belousov 	if (event->pulse && event->a.manual == 0) {
882*03ca6dbdSKonstantin Belousov 		event->a.signaled = 0;
883*03ca6dbdSKonstantin Belousov 		event->pulse = false;
884*03ca6dbdSKonstantin Belousov 	}
885*03ca6dbdSKonstantin Belousov }
886*03ca6dbdSKonstantin Belousov 
887*03ca6dbdSKonstantin Belousov static void
888*03ca6dbdSKonstantin Belousov ntsync_event_post_commit(struct ntsync_obj *obj,
889*03ca6dbdSKonstantin Belousov     struct ntsync_wait_state *state, int index)
890*03ca6dbdSKonstantin Belousov {
891*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_event *event;
892*03ca6dbdSKonstantin Belousov 
893*03ca6dbdSKonstantin Belousov 	MPASS(obj->type == NTSYNC_OBJ_EVENT);
894*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_ASSERT(obj->owner);
895*03ca6dbdSKonstantin Belousov 	event = OBJ_TO_EVENT(obj);
896*03ca6dbdSKonstantin Belousov 	if (event->a.manual == 0)
897*03ca6dbdSKonstantin Belousov 		event->a.signaled = 0;
898*03ca6dbdSKonstantin Belousov }
899*03ca6dbdSKonstantin Belousov 
900*03ca6dbdSKonstantin Belousov static int
901*03ca6dbdSKonstantin Belousov ntsync_event_close(struct file *fp, struct thread *td)
902*03ca6dbdSKonstantin Belousov {
903*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_event *event;
904*03ca6dbdSKonstantin Belousov 
905*03ca6dbdSKonstantin Belousov 	event = fp->f_data;
906*03ca6dbdSKonstantin Belousov 	ntsync_close_obj(&event->obj, td);
907*03ca6dbdSKonstantin Belousov 	free(event, M_NTSYNC);
908*03ca6dbdSKonstantin Belousov 	return (0);
909*03ca6dbdSKonstantin Belousov }
910*03ca6dbdSKonstantin Belousov 
911*03ca6dbdSKonstantin Belousov int
912*03ca6dbdSKonstantin Belousov ntsync_event_set(struct thread *td, struct file *fp, uint32_t *val)
913*03ca6dbdSKonstantin Belousov {
914*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
915*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_event *event;
916*03ca6dbdSKonstantin Belousov 	struct ntsync_priv *priv;
917*03ca6dbdSKonstantin Belousov 	uint32_t prev;
918*03ca6dbdSKonstantin Belousov 
919*03ca6dbdSKonstantin Belousov 	obj = fp->f_data;
920*03ca6dbdSKonstantin Belousov 	if (obj->type != NTSYNC_OBJ_EVENT)
921*03ca6dbdSKonstantin Belousov 		return (EINVAL);
922*03ca6dbdSKonstantin Belousov 	event = OBJ_TO_EVENT(obj);
923*03ca6dbdSKonstantin Belousov 	priv = obj->owner;
924*03ca6dbdSKonstantin Belousov 
925*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_LOCK(priv);
926*03ca6dbdSKonstantin Belousov 	prev = event->a.signaled;
927*03ca6dbdSKonstantin Belousov 	event->a.signaled = 1;
928*03ca6dbdSKonstantin Belousov 	ntsync_wakeup_waiters(obj);
929*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_UNLOCK(priv);
930*03ca6dbdSKonstantin Belousov 
931*03ca6dbdSKonstantin Belousov 	*val = prev;
932*03ca6dbdSKonstantin Belousov 	return (0);
933*03ca6dbdSKonstantin Belousov }
934*03ca6dbdSKonstantin Belousov 
935*03ca6dbdSKonstantin Belousov int
936*03ca6dbdSKonstantin Belousov ntsync_event_reset(struct thread *td, struct file *fp, uint32_t *val)
937*03ca6dbdSKonstantin Belousov {
938*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
939*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_event *event;
940*03ca6dbdSKonstantin Belousov 	struct ntsync_priv *priv;
941*03ca6dbdSKonstantin Belousov 	uint32_t prev;
942*03ca6dbdSKonstantin Belousov 
943*03ca6dbdSKonstantin Belousov 	obj = fp->f_data;
944*03ca6dbdSKonstantin Belousov 	if (obj->type != NTSYNC_OBJ_EVENT)
945*03ca6dbdSKonstantin Belousov 		return (EINVAL);
946*03ca6dbdSKonstantin Belousov 	event = OBJ_TO_EVENT(obj);
947*03ca6dbdSKonstantin Belousov 	priv = obj->owner;
948*03ca6dbdSKonstantin Belousov 
949*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_LOCK(priv);
950*03ca6dbdSKonstantin Belousov 	prev = event->a.signaled;
951*03ca6dbdSKonstantin Belousov 	event->a.signaled = 0;
952*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_UNLOCK(priv);
953*03ca6dbdSKonstantin Belousov 
954*03ca6dbdSKonstantin Belousov 	*val = prev;
955*03ca6dbdSKonstantin Belousov 	return (0);
956*03ca6dbdSKonstantin Belousov }
957*03ca6dbdSKonstantin Belousov 
958*03ca6dbdSKonstantin Belousov int
959*03ca6dbdSKonstantin Belousov ntsync_event_pulse(struct thread *td, struct file *fp, uint32_t *val)
960*03ca6dbdSKonstantin Belousov {
961*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
962*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_event *event;
963*03ca6dbdSKonstantin Belousov 	struct ntsync_priv *priv;
964*03ca6dbdSKonstantin Belousov 	uint32_t prev;
965*03ca6dbdSKonstantin Belousov 
966*03ca6dbdSKonstantin Belousov 	obj = fp->f_data;
967*03ca6dbdSKonstantin Belousov 	if (obj->type != NTSYNC_OBJ_EVENT)
968*03ca6dbdSKonstantin Belousov 		return (EINVAL);
969*03ca6dbdSKonstantin Belousov 	event = OBJ_TO_EVENT(obj);
970*03ca6dbdSKonstantin Belousov 	priv = obj->owner;
971*03ca6dbdSKonstantin Belousov 
972*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_LOCK(priv);
973*03ca6dbdSKonstantin Belousov 	prev = event->a.signaled;
974*03ca6dbdSKonstantin Belousov 	event->a.signaled = 1;
975*03ca6dbdSKonstantin Belousov 	event->pulse = true;
976*03ca6dbdSKonstantin Belousov 	ntsync_wakeup_waiters(obj);
977*03ca6dbdSKonstantin Belousov 	event->a.signaled = 0;
978*03ca6dbdSKonstantin Belousov 	event->pulse = false;
979*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_UNLOCK(priv);
980*03ca6dbdSKonstantin Belousov 
981*03ca6dbdSKonstantin Belousov 	*val = prev;
982*03ca6dbdSKonstantin Belousov 	return (0);
983*03ca6dbdSKonstantin Belousov }
984*03ca6dbdSKonstantin Belousov 
985*03ca6dbdSKonstantin Belousov int
986*03ca6dbdSKonstantin Belousov ntsync_event_read(struct thread *td, struct file *fp,
987*03ca6dbdSKonstantin Belousov     struct ntsync_event_args *a)
988*03ca6dbdSKonstantin Belousov {
989*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
990*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_event *event;
991*03ca6dbdSKonstantin Belousov 	struct ntsync_priv *priv;
992*03ca6dbdSKonstantin Belousov 
993*03ca6dbdSKonstantin Belousov 	obj = fp->f_data;
994*03ca6dbdSKonstantin Belousov 	if (obj->type != NTSYNC_OBJ_EVENT)
995*03ca6dbdSKonstantin Belousov 		return (EINVAL);
996*03ca6dbdSKonstantin Belousov 	event = OBJ_TO_EVENT(obj);
997*03ca6dbdSKonstantin Belousov 	priv = obj->owner;
998*03ca6dbdSKonstantin Belousov 
999*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_LOCK(priv);
1000*03ca6dbdSKonstantin Belousov 	*a = event->a;
1001*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_UNLOCK(priv);
1002*03ca6dbdSKonstantin Belousov 
1003*03ca6dbdSKonstantin Belousov 	return (0);
1004*03ca6dbdSKonstantin Belousov }
1005*03ca6dbdSKonstantin Belousov 
1006*03ca6dbdSKonstantin Belousov static int
1007*03ca6dbdSKonstantin Belousov ntsync_event_ioctl(struct file *fp, u_long com, void *data,
1008*03ca6dbdSKonstantin Belousov     struct ucred *active_cred, struct thread *td)
1009*03ca6dbdSKonstantin Belousov {
1010*03ca6dbdSKonstantin Belousov 	int error;
1011*03ca6dbdSKonstantin Belousov 
1012*03ca6dbdSKonstantin Belousov 	switch (com) {
1013*03ca6dbdSKonstantin Belousov 	case NTSYNC_IOC_EVENT_SET:
1014*03ca6dbdSKonstantin Belousov 		error = ntsync_event_set(td, fp, data);
1015*03ca6dbdSKonstantin Belousov 		break;
1016*03ca6dbdSKonstantin Belousov 	case NTSYNC_IOC_EVENT_RESET:
1017*03ca6dbdSKonstantin Belousov 		error = ntsync_event_reset(td, fp, data);
1018*03ca6dbdSKonstantin Belousov 		break;
1019*03ca6dbdSKonstantin Belousov 	case NTSYNC_IOC_EVENT_PULSE:
1020*03ca6dbdSKonstantin Belousov 		error = ntsync_event_pulse(td, fp, data);
1021*03ca6dbdSKonstantin Belousov 		break;
1022*03ca6dbdSKonstantin Belousov 	case NTSYNC_IOC_EVENT_READ:
1023*03ca6dbdSKonstantin Belousov 		error = ntsync_event_read(td, fp, data);
1024*03ca6dbdSKonstantin Belousov 		break;
1025*03ca6dbdSKonstantin Belousov 	default:
1026*03ca6dbdSKonstantin Belousov 		error = ENOTTY;
1027*03ca6dbdSKonstantin Belousov 		break;
1028*03ca6dbdSKonstantin Belousov 	}
1029*03ca6dbdSKonstantin Belousov 	return (error);
1030*03ca6dbdSKonstantin Belousov }
1031*03ca6dbdSKonstantin Belousov 
1032*03ca6dbdSKonstantin Belousov static int
1033*03ca6dbdSKonstantin Belousov ntsync_event_stat(struct file *fp, struct stat *sbp, struct ucred *cred)
1034*03ca6dbdSKonstantin Belousov {
1035*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
1036*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_event *event;
1037*03ca6dbdSKonstantin Belousov 
1038*03ca6dbdSKonstantin Belousov 	MPASS(fp->f_type == DTYPE_NTSYNC);
1039*03ca6dbdSKonstantin Belousov 	obj = fp->f_data;
1040*03ca6dbdSKonstantin Belousov 	MPASS(obj->type == NTSYNC_OBJ_EVENT);
1041*03ca6dbdSKonstantin Belousov 	event = OBJ_TO_EVENT(obj);
1042*03ca6dbdSKonstantin Belousov 
1043*03ca6dbdSKonstantin Belousov 	memset(sbp, 0, sizeof(*sbp));
1044*03ca6dbdSKonstantin Belousov 	sbp->st_mode = S_IFREG /* XXXKIB */ | S_IRUSR | S_IWUSR;
1045*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_LOCK(obj->owner);
1046*03ca6dbdSKonstantin Belousov 	sbp->st_size = event->a.signaled;
1047*03ca6dbdSKonstantin Belousov 	sbp->st_nlink = event->a.manual;
1048*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_UNLOCK(obj->owner);
1049*03ca6dbdSKonstantin Belousov 	return (0);
1050*03ca6dbdSKonstantin Belousov }
1051*03ca6dbdSKonstantin Belousov 
1052*03ca6dbdSKonstantin Belousov static int
1053*03ca6dbdSKonstantin Belousov ntsync_event_fill_kinfo(struct file *fp, struct kinfo_file *kif,
1054*03ca6dbdSKonstantin Belousov     struct filedesc *fdp)
1055*03ca6dbdSKonstantin Belousov {
1056*03ca6dbdSKonstantin Belousov 	// XXXKIB
1057*03ca6dbdSKonstantin Belousov 	return (0);
1058*03ca6dbdSKonstantin Belousov }
1059*03ca6dbdSKonstantin Belousov 
1060*03ca6dbdSKonstantin Belousov struct fileops ntsync_event_fops = {
1061*03ca6dbdSKonstantin Belousov 	.fo_read = invfo_rdwr,
1062*03ca6dbdSKonstantin Belousov 	.fo_write = invfo_rdwr,
1063*03ca6dbdSKonstantin Belousov 	.fo_truncate = invfo_truncate,
1064*03ca6dbdSKonstantin Belousov 	.fo_ioctl = ntsync_event_ioctl,
1065*03ca6dbdSKonstantin Belousov 	.fo_poll = invfo_poll,
1066*03ca6dbdSKonstantin Belousov 	.fo_kqfilter = invfo_kqfilter,
1067*03ca6dbdSKonstantin Belousov 	.fo_stat = ntsync_event_stat,
1068*03ca6dbdSKonstantin Belousov 	.fo_close = ntsync_event_close,
1069*03ca6dbdSKonstantin Belousov 	.fo_chmod = invfo_chmod,
1070*03ca6dbdSKonstantin Belousov 	.fo_chown = invfo_chown,
1071*03ca6dbdSKonstantin Belousov 	.fo_sendfile = invfo_sendfile,
1072*03ca6dbdSKonstantin Belousov 	.fo_fill_kinfo = ntsync_event_fill_kinfo,
1073*03ca6dbdSKonstantin Belousov 	.fo_flags = DFLAG_PASSABLE,
1074*03ca6dbdSKonstantin Belousov };
1075*03ca6dbdSKonstantin Belousov 
1076*03ca6dbdSKonstantin Belousov static int
1077*03ca6dbdSKonstantin Belousov ntsync_create_event(struct ntsync_event_args *args, struct ntsync_priv *priv,
1078*03ca6dbdSKonstantin Belousov     struct thread *td)
1079*03ca6dbdSKonstantin Belousov {
1080*03ca6dbdSKonstantin Belousov 	struct ntsync_obj_event *event;
1081*03ca6dbdSKonstantin Belousov 	int error;
1082*03ca6dbdSKonstantin Belousov 
1083*03ca6dbdSKonstantin Belousov 	event = malloc(sizeof(*event), M_NTSYNC, M_WAITOK | M_ZERO);
1084*03ca6dbdSKonstantin Belousov 	event->obj.type = NTSYNC_OBJ_EVENT;
1085*03ca6dbdSKonstantin Belousov 	event->obj.is_signaled = ntsync_event_is_signaled;
1086*03ca6dbdSKonstantin Belousov 	event->obj.consume = ntsync_event_consume;
1087*03ca6dbdSKonstantin Belousov 	event->obj.prepare = ntsync_event_prepare;
1088*03ca6dbdSKonstantin Belousov 	event->obj.commit = ntsync_event_commit;
1089*03ca6dbdSKonstantin Belousov 	event->obj.post_commit = ntsync_event_post_commit;
1090*03ca6dbdSKonstantin Belousov 	event->a = *args;
1091*03ca6dbdSKonstantin Belousov 
1092*03ca6dbdSKonstantin Belousov 	error = ntsync_create_obj(&event->obj, &ntsync_event_fops, priv, td);
1093*03ca6dbdSKonstantin Belousov 	if (error != 0)
1094*03ca6dbdSKonstantin Belousov 		free(event, M_NTSYNC);
1095*03ca6dbdSKonstantin Belousov 
1096*03ca6dbdSKonstantin Belousov 	return (error);
1097*03ca6dbdSKonstantin Belousov }
1098*03ca6dbdSKonstantin Belousov 
1099*03ca6dbdSKonstantin Belousov static void
1100*03ca6dbdSKonstantin Belousov ntsync_free_priv(struct ntsync_priv *priv)
1101*03ca6dbdSKonstantin Belousov {
1102*03ca6dbdSKonstantin Belousov 	bool do_free;
1103*03ca6dbdSKonstantin Belousov 
1104*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_LOCK(priv);
1105*03ca6dbdSKonstantin Belousov 	do_free = priv->closed && priv->objs_cnt == 0;
1106*03ca6dbdSKonstantin Belousov 	NTSYNC_PRIV_UNLOCK(priv);
1107*03ca6dbdSKonstantin Belousov 	if (do_free) {
1108*03ca6dbdSKonstantin Belousov 		mtx_destroy(&priv->lock);
1109*03ca6dbdSKonstantin Belousov 		free(priv, M_NTSYNC);
1110*03ca6dbdSKonstantin Belousov 	}
1111*03ca6dbdSKonstantin Belousov }
1112*03ca6dbdSKonstantin Belousov 
1113*03ca6dbdSKonstantin Belousov static void
1114*03ca6dbdSKonstantin Belousov ntsync_priv_dtr(void *data)
1115*03ca6dbdSKonstantin Belousov {
1116*03ca6dbdSKonstantin Belousov 	ntsync_free_priv(data);
1117*03ca6dbdSKonstantin Belousov }
1118*03ca6dbdSKonstantin Belousov 
1119*03ca6dbdSKonstantin Belousov static int
1120*03ca6dbdSKonstantin Belousov ntsync_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
1121*03ca6dbdSKonstantin Belousov {
1122*03ca6dbdSKonstantin Belousov 	struct ntsync_priv *priv;
1123*03ca6dbdSKonstantin Belousov 
1124*03ca6dbdSKonstantin Belousov 	priv = malloc(sizeof(*priv), M_NTSYNC, M_WAITOK);
1125*03ca6dbdSKonstantin Belousov 	priv->closed = false;
1126*03ca6dbdSKonstantin Belousov 	priv->objs_cnt = 0;
1127*03ca6dbdSKonstantin Belousov 	mtx_init(&priv->lock, "ntsync", "ntsync", MTX_DEF | MTX_NEW);
1128*03ca6dbdSKonstantin Belousov 	devfs_set_cdevpriv(priv, ntsync_priv_dtr);
1129*03ca6dbdSKonstantin Belousov 	return (0);
1130*03ca6dbdSKonstantin Belousov }
1131*03ca6dbdSKonstantin Belousov 
1132*03ca6dbdSKonstantin Belousov static int
1133*03ca6dbdSKonstantin Belousov ntsync_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
1134*03ca6dbdSKonstantin Belousov {
1135*03ca6dbdSKonstantin Belousov 	struct ntsync_priv *priv;
1136*03ca6dbdSKonstantin Belousov 	void *a;
1137*03ca6dbdSKonstantin Belousov 	int error;
1138*03ca6dbdSKonstantin Belousov 
1139*03ca6dbdSKonstantin Belousov 	error = devfs_get_cdevpriv(&a);
1140*03ca6dbdSKonstantin Belousov 	if (error == 0) {
1141*03ca6dbdSKonstantin Belousov 		priv = a;
1142*03ca6dbdSKonstantin Belousov 		NTSYNC_PRIV_LOCK(priv);
1143*03ca6dbdSKonstantin Belousov 		priv->closed = true;
1144*03ca6dbdSKonstantin Belousov 		NTSYNC_PRIV_UNLOCK(priv);
1145*03ca6dbdSKonstantin Belousov 	}
1146*03ca6dbdSKonstantin Belousov 	devfs_clear_cdevpriv();
1147*03ca6dbdSKonstantin Belousov 	return (0);
1148*03ca6dbdSKonstantin Belousov }
1149*03ca6dbdSKonstantin Belousov 
1150*03ca6dbdSKonstantin Belousov static int
1151*03ca6dbdSKonstantin Belousov ntsync_wait_state_get(struct ntsync_wait_args *nwa, u_long cmd,
1152*03ca6dbdSKonstantin Belousov     struct ntsync_priv *owner, struct ntsync_wait_state **statep,
1153*03ca6dbdSKonstantin Belousov     struct thread *td)
1154*03ca6dbdSKonstantin Belousov {
1155*03ca6dbdSKonstantin Belousov 	struct ntsync_wait_state *state;
1156*03ca6dbdSKonstantin Belousov 	struct ntsync_obj *obj;
1157*03ca6dbdSKonstantin Belousov 	struct bintime btb;
1158*03ca6dbdSKonstantin Belousov 	int error, i, j;
1159*03ca6dbdSKonstantin Belousov 
1160*03ca6dbdSKonstantin Belousov 	if (nwa->count > NTSYNC_MAX_WAIT_COUNT)
1161*03ca6dbdSKonstantin Belousov 		return (EINVAL);
1162*03ca6dbdSKonstantin Belousov 	if ((nwa->flags & ~NTSYNC_WAIT_REALTIME) != 0)
1163*03ca6dbdSKonstantin Belousov 		return (EINVAL);
1164*03ca6dbdSKonstantin Belousov 
1165*03ca6dbdSKonstantin Belousov 	state = malloc(sizeof(*state), M_NTSYNC, M_WAITOK | M_ZERO);
1166*03ca6dbdSKonstantin Belousov 	state->nwa = nwa;
1167*03ca6dbdSKonstantin Belousov 	state->owner = owner;
1168*03ca6dbdSKonstantin Belousov 	state->all = cmd == NTSYNC_IOC_WAIT_ALL;
1169*03ca6dbdSKonstantin Belousov 	state->any = !state->all;
1170*03ca6dbdSKonstantin Belousov 	error = copyin((void *)(uintptr_t)nwa->objs, &state->fds[0],
1171*03ca6dbdSKonstantin Belousov 	    nwa->count * sizeof(state->fds[0]));
1172*03ca6dbdSKonstantin Belousov 	if (error != 0)
1173*03ca6dbdSKonstantin Belousov 		return (error);
1174*03ca6dbdSKonstantin Belousov 
1175*03ca6dbdSKonstantin Belousov 	i = 0;
1176*03ca6dbdSKonstantin Belousov 	if (nwa->alert != 0) {
1177*03ca6dbdSKonstantin Belousov 		error = fget_cap(td, nwa->alert, &cap_no_rights, NULL,
1178*03ca6dbdSKonstantin Belousov 		    &state->fp_alert, NULL);
1179*03ca6dbdSKonstantin Belousov 		if (error != 0) {
1180*03ca6dbdSKonstantin Belousov 			state->fp_alert = NULL;
1181*03ca6dbdSKonstantin Belousov 			goto error_out;
1182*03ca6dbdSKonstantin Belousov 		}
1183*03ca6dbdSKonstantin Belousov 		if (state->fp_alert->f_type != DTYPE_NTSYNC) {
1184*03ca6dbdSKonstantin Belousov 			error = EINVAL;
1185*03ca6dbdSKonstantin Belousov 			goto error_out;
1186*03ca6dbdSKonstantin Belousov 		}
1187*03ca6dbdSKonstantin Belousov 		obj = state->fp_alert->f_data;
1188*03ca6dbdSKonstantin Belousov 		if (obj->type != NTSYNC_OBJ_EVENT || obj->owner != owner) {
1189*03ca6dbdSKonstantin Belousov 			error = EINVAL;
1190*03ca6dbdSKonstantin Belousov 			goto error_out;
1191*03ca6dbdSKonstantin Belousov 		}
1192*03ca6dbdSKonstantin Belousov 		state->alert_event = OBJ_TO_EVENT(obj);
1193*03ca6dbdSKonstantin Belousov 	}
1194*03ca6dbdSKonstantin Belousov 
1195*03ca6dbdSKonstantin Belousov 	for (; i < nwa->count; i++) {
1196*03ca6dbdSKonstantin Belousov 		error = fget_cap(td, state->fds[i], &cap_no_rights, NULL,
1197*03ca6dbdSKonstantin Belousov 		    &state->fps[i], NULL);
1198*03ca6dbdSKonstantin Belousov 		if (error != 0) {
1199*03ca6dbdSKonstantin Belousov 			state->fps[i] = NULL;
1200*03ca6dbdSKonstantin Belousov 			goto error_out;
1201*03ca6dbdSKonstantin Belousov 		}
1202*03ca6dbdSKonstantin Belousov 		if (state->fps[i]->f_type != DTYPE_NTSYNC ||
1203*03ca6dbdSKonstantin Belousov 		    (obj = state->fps[i]->f_data)->owner != owner) {
1204*03ca6dbdSKonstantin Belousov 			i++;
1205*03ca6dbdSKonstantin Belousov 			error = EINVAL;
1206*03ca6dbdSKonstantin Belousov 			goto error_out;
1207*03ca6dbdSKonstantin Belousov 		}
1208*03ca6dbdSKonstantin Belousov 	}
1209*03ca6dbdSKonstantin Belousov 
1210*03ca6dbdSKonstantin Belousov 	state->obj_count = nwa->count;
1211*03ca6dbdSKonstantin Belousov 	for (i = 0; i < nwa->count; i++)
1212*03ca6dbdSKonstantin Belousov 		state->objs[i] = state->fps[i]->f_data;
1213*03ca6dbdSKonstantin Belousov 	if (state->alert_event != NULL) {
1214*03ca6dbdSKonstantin Belousov 		state->objs[i] = &state->alert_event->obj;
1215*03ca6dbdSKonstantin Belousov 		state->obj_count++;
1216*03ca6dbdSKonstantin Belousov 	}
1217*03ca6dbdSKonstantin Belousov 
1218*03ca6dbdSKonstantin Belousov 	if (state->all) {
1219*03ca6dbdSKonstantin Belousov 		/* Check no dups */
1220*03ca6dbdSKonstantin Belousov 		for (i = 0; i < state->obj_count; i++) {
1221*03ca6dbdSKonstantin Belousov 			obj = state->objs[i];
1222*03ca6dbdSKonstantin Belousov 			for (j = i + 1; j < state->obj_count; j++) {
1223*03ca6dbdSKonstantin Belousov 				if (obj == state->objs[j]) {
1224*03ca6dbdSKonstantin Belousov 					i = state->obj_count;
1225*03ca6dbdSKonstantin Belousov 					error = EINVAL;
1226*03ca6dbdSKonstantin Belousov 					goto error_out;
1227*03ca6dbdSKonstantin Belousov 				}
1228*03ca6dbdSKonstantin Belousov 			}
1229*03ca6dbdSKonstantin Belousov 		}
1230*03ca6dbdSKonstantin Belousov 	}
1231*03ca6dbdSKonstantin Belousov 
1232*03ca6dbdSKonstantin Belousov 	if (nwa->timeout == UINT64_MAX) {
1233*03ca6dbdSKonstantin Belousov 		state->sb = 0;
1234*03ca6dbdSKonstantin Belousov 	} else {
1235*03ca6dbdSKonstantin Belousov 		state->sb = nstosbt(nwa->timeout);
1236*03ca6dbdSKonstantin Belousov 		if ((nwa->flags & NTSYNC_WAIT_REALTIME) != 0) {
1237*03ca6dbdSKonstantin Belousov 			getboottimebin(&btb);
1238*03ca6dbdSKonstantin Belousov 			state->sb += bttosbt(btb);
1239*03ca6dbdSKonstantin Belousov 		}
1240*03ca6dbdSKonstantin Belousov 	}
1241*03ca6dbdSKonstantin Belousov 
1242*03ca6dbdSKonstantin Belousov 	*statep = state;
1243*03ca6dbdSKonstantin Belousov 	return (0);
1244*03ca6dbdSKonstantin Belousov 
1245*03ca6dbdSKonstantin Belousov error_out:
1246*03ca6dbdSKonstantin Belousov 	for (j = 0; j < i; j++)
1247*03ca6dbdSKonstantin Belousov 		fdrop(state->fps[j], td);
1248*03ca6dbdSKonstantin Belousov 	if (state->fp_alert != NULL)
1249*03ca6dbdSKonstantin Belousov 		fdrop(state->fp_alert, td);
1250*03ca6dbdSKonstantin Belousov 	return (error);
1251*03ca6dbdSKonstantin Belousov }
1252*03ca6dbdSKonstantin Belousov 
1253*03ca6dbdSKonstantin Belousov static void
1254*03ca6dbdSKonstantin Belousov ntsync_wait_state_put(struct ntsync_wait_state *state, struct thread *td)
1255*03ca6dbdSKonstantin Belousov {
1256*03ca6dbdSKonstantin Belousov 	int i;
1257*03ca6dbdSKonstantin Belousov 
1258*03ca6dbdSKonstantin Belousov 	for (i = 0; i < state->nwa->count; i++)
1259*03ca6dbdSKonstantin Belousov 		fdrop(state->fps[i], td);
1260*03ca6dbdSKonstantin Belousov 	if (state->fp_alert != NULL)
1261*03ca6dbdSKonstantin Belousov 		fdrop(state->fp_alert, td);
1262*03ca6dbdSKonstantin Belousov 	free(state, M_NTSYNC);
1263*03ca6dbdSKonstantin Belousov }
1264*03ca6dbdSKonstantin Belousov 
1265*03ca6dbdSKonstantin Belousov static int
1266*03ca6dbdSKonstantin Belousov ntsync_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
1267*03ca6dbdSKonstantin Belousov     struct thread *td)
1268*03ca6dbdSKonstantin Belousov {
1269*03ca6dbdSKonstantin Belousov 	struct ntsync_priv *owner;
1270*03ca6dbdSKonstantin Belousov 	struct ntsync_wait_args *nwa;
1271*03ca6dbdSKonstantin Belousov 	struct ntsync_wait_state *state;
1272*03ca6dbdSKonstantin Belousov 	void *a;
1273*03ca6dbdSKonstantin Belousov 	int error;
1274*03ca6dbdSKonstantin Belousov 
1275*03ca6dbdSKonstantin Belousov 	error = devfs_get_cdevpriv(&a);
1276*03ca6dbdSKonstantin Belousov 	if (error != 0)
1277*03ca6dbdSKonstantin Belousov 		return (error);
1278*03ca6dbdSKonstantin Belousov 	owner = a;
1279*03ca6dbdSKonstantin Belousov 
1280*03ca6dbdSKonstantin Belousov 	switch (cmd) {
1281*03ca6dbdSKonstantin Belousov 	case NTSYNC_IOC_CREATE_SEM:
1282*03ca6dbdSKonstantin Belousov 		error = ntsync_create_sem((struct ntsync_sem_args *)data,
1283*03ca6dbdSKonstantin Belousov 		    owner, td);
1284*03ca6dbdSKonstantin Belousov 		break;
1285*03ca6dbdSKonstantin Belousov 	case NTSYNC_IOC_CREATE_MUTEX:
1286*03ca6dbdSKonstantin Belousov 		error = ntsync_create_mutex((struct ntsync_mutex_args *)data,
1287*03ca6dbdSKonstantin Belousov 		    owner, td);
1288*03ca6dbdSKonstantin Belousov 		break;
1289*03ca6dbdSKonstantin Belousov 	case NTSYNC_IOC_CREATE_EVENT:
1290*03ca6dbdSKonstantin Belousov 		error = ntsync_create_event((struct ntsync_event_args *)data,
1291*03ca6dbdSKonstantin Belousov 		    owner, td);
1292*03ca6dbdSKonstantin Belousov 		break;
1293*03ca6dbdSKonstantin Belousov 	case NTSYNC_IOC_WAIT_ANY:
1294*03ca6dbdSKonstantin Belousov 		nwa = (struct ntsync_wait_args *)data;
1295*03ca6dbdSKonstantin Belousov 		error = ntsync_wait_state_get(nwa, cmd, owner, &state, td);
1296*03ca6dbdSKonstantin Belousov 		if (error != 0)
1297*03ca6dbdSKonstantin Belousov 			break;
1298*03ca6dbdSKonstantin Belousov 		error = ntsync_wait(state, td);
1299*03ca6dbdSKonstantin Belousov 		if (error == 0) {
1300*03ca6dbdSKonstantin Belousov 			nwa->index = state->index;
1301*03ca6dbdSKonstantin Belousov 			error = ntsync_ioctl_copyout(td, nwa, sizeof(*nwa));
1302*03ca6dbdSKonstantin Belousov 			if (error == 0)
1303*03ca6dbdSKonstantin Belousov 				error = state->error;
1304*03ca6dbdSKonstantin Belousov 		}
1305*03ca6dbdSKonstantin Belousov 		ntsync_wait_state_put(state, td);
1306*03ca6dbdSKonstantin Belousov 		break;
1307*03ca6dbdSKonstantin Belousov 	case NTSYNC_IOC_WAIT_ALL:
1308*03ca6dbdSKonstantin Belousov 		nwa = (struct ntsync_wait_args *)data;
1309*03ca6dbdSKonstantin Belousov 		error = ntsync_wait_state_get(nwa, cmd, owner, &state, td);
1310*03ca6dbdSKonstantin Belousov 		if (error != 0)
1311*03ca6dbdSKonstantin Belousov 			break;
1312*03ca6dbdSKonstantin Belousov 		error = ntsync_wait(state, td);
1313*03ca6dbdSKonstantin Belousov 		if (error == 0) {
1314*03ca6dbdSKonstantin Belousov 			nwa->index = state->index;
1315*03ca6dbdSKonstantin Belousov 			error = ntsync_ioctl_copyout(td, nwa, sizeof(*nwa));
1316*03ca6dbdSKonstantin Belousov 			if (error == 0)
1317*03ca6dbdSKonstantin Belousov 				error = state->error;
1318*03ca6dbdSKonstantin Belousov 		}
1319*03ca6dbdSKonstantin Belousov 		ntsync_wait_state_put(state, td);
1320*03ca6dbdSKonstantin Belousov 		break;
1321*03ca6dbdSKonstantin Belousov 
1322*03ca6dbdSKonstantin Belousov 	default:
1323*03ca6dbdSKonstantin Belousov 		error = ENOTTY;
1324*03ca6dbdSKonstantin Belousov 		break;
1325*03ca6dbdSKonstantin Belousov 	}
1326*03ca6dbdSKonstantin Belousov 	return (error);
1327*03ca6dbdSKonstantin Belousov }
1328*03ca6dbdSKonstantin Belousov 
1329*03ca6dbdSKonstantin Belousov struct cdevsw ntsync_cdevsw = {
1330*03ca6dbdSKonstantin Belousov 	.d_version =	D_VERSION,
1331*03ca6dbdSKonstantin Belousov 	.d_flags =	0,
1332*03ca6dbdSKonstantin Belousov 	.d_open =	ntsync_open,
1333*03ca6dbdSKonstantin Belousov 	.d_close =	ntsync_close,
1334*03ca6dbdSKonstantin Belousov 	.d_ioctl =	ntsync_ioctl,
1335*03ca6dbdSKonstantin Belousov 	.d_name =	"ntsync",
1336*03ca6dbdSKonstantin Belousov };
1337*03ca6dbdSKonstantin Belousov 
1338*03ca6dbdSKonstantin Belousov static int
1339*03ca6dbdSKonstantin Belousov ntsync_modevent(module_t mod __unused, int type, void *data __unused)
1340*03ca6dbdSKonstantin Belousov {
1341*03ca6dbdSKonstantin Belousov 	struct make_dev_args mda;
1342*03ca6dbdSKonstantin Belousov 	int error;
1343*03ca6dbdSKonstantin Belousov 
1344*03ca6dbdSKonstantin Belousov 	error = 0;
1345*03ca6dbdSKonstantin Belousov 	switch (type) {
1346*03ca6dbdSKonstantin Belousov 	case MOD_LOAD:
1347*03ca6dbdSKonstantin Belousov 		make_dev_args_init(&mda);
1348*03ca6dbdSKonstantin Belousov 		mda.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME;
1349*03ca6dbdSKonstantin Belousov 		mda.mda_devsw = &ntsync_cdevsw;
1350*03ca6dbdSKonstantin Belousov 		mda.mda_uid = UID_ROOT;
1351*03ca6dbdSKonstantin Belousov 		mda.mda_gid = GID_GAMES;
1352*03ca6dbdSKonstantin Belousov 		mda.mda_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
1353*03ca6dbdSKonstantin Belousov 		    S_IROTH | S_IWOTH;
1354*03ca6dbdSKonstantin Belousov 
1355*03ca6dbdSKonstantin Belousov 		error = make_dev_s(&mda, &ntsync_cdev, "ntsync");
1356*03ca6dbdSKonstantin Belousov 		if (error != 0) {
1357*03ca6dbdSKonstantin Belousov 			printf("cannot create ntsync dev err %d\n", error);
1358*03ca6dbdSKonstantin Belousov 			break;
1359*03ca6dbdSKonstantin Belousov 		}
1360*03ca6dbdSKonstantin Belousov 		if (bootverbose)
1361*03ca6dbdSKonstantin Belousov 			printf("ntsync\n");
1362*03ca6dbdSKonstantin Belousov 		break;
1363*03ca6dbdSKonstantin Belousov 
1364*03ca6dbdSKonstantin Belousov 	case MOD_UNLOAD:
1365*03ca6dbdSKonstantin Belousov 		destroy_dev(ntsync_cdev);
1366*03ca6dbdSKonstantin Belousov 		break;
1367*03ca6dbdSKonstantin Belousov 
1368*03ca6dbdSKonstantin Belousov 	case MOD_SHUTDOWN:
1369*03ca6dbdSKonstantin Belousov 		break;
1370*03ca6dbdSKonstantin Belousov 
1371*03ca6dbdSKonstantin Belousov 	default:
1372*03ca6dbdSKonstantin Belousov 		error = EOPNOTSUPP;
1373*03ca6dbdSKonstantin Belousov 	}
1374*03ca6dbdSKonstantin Belousov 
1375*03ca6dbdSKonstantin Belousov 	return (error);
1376*03ca6dbdSKonstantin Belousov }
1377*03ca6dbdSKonstantin Belousov 
1378*03ca6dbdSKonstantin Belousov DEV_MODULE(ntsync, ntsync_modevent, NULL);
1379*03ca6dbdSKonstantin Belousov MODULE_VERSION(ntsync, 1);
1380