103ca6dbdSKonstantin Belousov /*
203ca6dbdSKonstantin Belousov * SPDX-License-Identifier: BSD-2-Clause
303ca6dbdSKonstantin Belousov *
403ca6dbdSKonstantin Belousov * Copyright 2026 The FreeBSD Foundation
503ca6dbdSKonstantin Belousov *
603ca6dbdSKonstantin Belousov * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
703ca6dbdSKonstantin Belousov * under sponsorship from the FreeBSD Foundation.
803ca6dbdSKonstantin Belousov */
903ca6dbdSKonstantin Belousov
1003ca6dbdSKonstantin Belousov #include <sys/systm.h>
1103ca6dbdSKonstantin Belousov #include <sys/conf.h>
1203ca6dbdSKonstantin Belousov #include <sys/fcntl.h>
1303ca6dbdSKonstantin Belousov #include <sys/file.h>
1403ca6dbdSKonstantin Belousov #include <sys/filedesc.h>
1503ca6dbdSKonstantin Belousov #include <sys/kernel.h>
1603ca6dbdSKonstantin Belousov #include <sys/limits.h>
1703ca6dbdSKonstantin Belousov #include <sys/malloc.h>
1803ca6dbdSKonstantin Belousov #include <sys/module.h>
1903ca6dbdSKonstantin Belousov #include <sys/proc.h>
2003ca6dbdSKonstantin Belousov #include <sys/stat.h>
2103ca6dbdSKonstantin Belousov #include <sys/sysent.h>
22*d0ea3affSKonstantin Belousov #include <sys/user.h>
2303ca6dbdSKonstantin Belousov #include <dev/ntsync/ntsyncvar.h>
2403ca6dbdSKonstantin Belousov
2503ca6dbdSKonstantin Belousov static struct cdev *ntsync_cdev;
2603ca6dbdSKonstantin Belousov MALLOC_DEFINE(M_NTSYNC, "ntsync", "ntsync");
2703ca6dbdSKonstantin Belousov
2803ca6dbdSKonstantin Belousov static void ntsync_free_priv(struct ntsync_priv *priv);
2903ca6dbdSKonstantin Belousov
3003ca6dbdSKonstantin Belousov /*
3103ca6dbdSKonstantin Belousov * Returning error from an ioctl handler prevents the generic ioctl
3203ca6dbdSKonstantin Belousov * code from copying out the result. Use direct access to ioctl(2)
3303ca6dbdSKonstantin Belousov * args to get the parameters block pointer to implement Linux
3403ca6dbdSKonstantin Belousov * semantic of both returning an error and updating the parameters
3503ca6dbdSKonstantin Belousov * block.
3603ca6dbdSKonstantin Belousov */
3703ca6dbdSKonstantin Belousov static int
ntsync_ioctl_copyout(struct thread * td,const void * ptr,size_t sz)3803ca6dbdSKonstantin Belousov ntsync_ioctl_copyout(struct thread *td, const void *ptr, size_t sz)
3903ca6dbdSKonstantin Belousov {
4003ca6dbdSKonstantin Belousov void *uptr;
4103ca6dbdSKonstantin Belousov
4203ca6dbdSKonstantin Belousov if (SV_PROC_ABI(td->td_proc) != SV_ABI_FREEBSD)
4303ca6dbdSKonstantin Belousov return (0);
4403ca6dbdSKonstantin Belousov uptr = (void *)(uintptr_t)td->td_sa.args[2];
4503ca6dbdSKonstantin Belousov return (copyout(ptr, uptr, sz));
4603ca6dbdSKonstantin Belousov }
4703ca6dbdSKonstantin Belousov
4803ca6dbdSKonstantin Belousov static bool
ntsync_wait_any(struct ntsync_wait_state * state)4903ca6dbdSKonstantin Belousov ntsync_wait_any(struct ntsync_wait_state *state)
5003ca6dbdSKonstantin Belousov {
5103ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
5203ca6dbdSKonstantin Belousov int i;
5303ca6dbdSKonstantin Belousov
5403ca6dbdSKonstantin Belousov MPASS(state->any);
5503ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(state->owner);
5603ca6dbdSKonstantin Belousov
5703ca6dbdSKonstantin Belousov for (i = 0; i < state->obj_count; i++) {
5803ca6dbdSKonstantin Belousov obj = state->objs[i];
5903ca6dbdSKonstantin Belousov if (obj->is_signaled(obj, state, i)) {
6003ca6dbdSKonstantin Belousov state->index = i;
6103ca6dbdSKonstantin Belousov obj->consume(obj, state, state->index);
6203ca6dbdSKonstantin Belousov return (true);
6303ca6dbdSKonstantin Belousov }
6403ca6dbdSKonstantin Belousov }
6503ca6dbdSKonstantin Belousov return (false);
6603ca6dbdSKonstantin Belousov }
6703ca6dbdSKonstantin Belousov
6803ca6dbdSKonstantin Belousov static bool
ntsync_wait_all_prepare(struct ntsync_wait_state * state,bool * stop)6903ca6dbdSKonstantin Belousov ntsync_wait_all_prepare(struct ntsync_wait_state *state, bool *stop)
7003ca6dbdSKonstantin Belousov {
7103ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
7203ca6dbdSKonstantin Belousov int alerti, i;
7303ca6dbdSKonstantin Belousov bool first;
7403ca6dbdSKonstantin Belousov
7503ca6dbdSKonstantin Belousov MPASS(state->all);
7603ca6dbdSKonstantin Belousov MPASS(state->error == 0);
7703ca6dbdSKonstantin Belousov MPASS(!*stop);
7803ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(state->owner);
7903ca6dbdSKonstantin Belousov
8003ca6dbdSKonstantin Belousov alerti = state->alert_event == NULL ? 0 : 1;
8103ca6dbdSKonstantin Belousov first = true;
8203ca6dbdSKonstantin Belousov
8303ca6dbdSKonstantin Belousov for (i = 0; i < state->obj_count - alerti; i++) {
8403ca6dbdSKonstantin Belousov obj = state->objs[i];
8503ca6dbdSKonstantin Belousov if (!obj->prepare(obj, state, i, stop))
8603ca6dbdSKonstantin Belousov return (false);
8703ca6dbdSKonstantin Belousov if (*stop) {
8803ca6dbdSKonstantin Belousov MPASS(state->error != 0);
8903ca6dbdSKonstantin Belousov return (false);
9003ca6dbdSKonstantin Belousov }
9103ca6dbdSKonstantin Belousov MPASS (state->error == 0);
9203ca6dbdSKonstantin Belousov if (first) {
9303ca6dbdSKonstantin Belousov first = false;
9403ca6dbdSKonstantin Belousov state->index = i;
9503ca6dbdSKonstantin Belousov }
9603ca6dbdSKonstantin Belousov }
9703ca6dbdSKonstantin Belousov return (true);
9803ca6dbdSKonstantin Belousov }
9903ca6dbdSKonstantin Belousov
10003ca6dbdSKonstantin Belousov static void
ntsync_wait_all_commit(struct ntsync_wait_state * state)10103ca6dbdSKonstantin Belousov ntsync_wait_all_commit(struct ntsync_wait_state *state)
10203ca6dbdSKonstantin Belousov {
10303ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
10403ca6dbdSKonstantin Belousov int i, alerti;
10503ca6dbdSKonstantin Belousov
10603ca6dbdSKonstantin Belousov MPASS(state->all);
10703ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(state->owner);
10803ca6dbdSKonstantin Belousov alerti = state->alert_event == NULL ? 0 : 1;
10903ca6dbdSKonstantin Belousov
11003ca6dbdSKonstantin Belousov for (i = 0; i < state->obj_count - alerti; i++) {
11103ca6dbdSKonstantin Belousov obj = state->objs[i];
11203ca6dbdSKonstantin Belousov obj->commit(obj, state, i);
11303ca6dbdSKonstantin Belousov }
11403ca6dbdSKonstantin Belousov }
11503ca6dbdSKonstantin Belousov
11603ca6dbdSKonstantin Belousov static void
ntsync_wait_link_waiters(struct ntsync_wait_state * state)11703ca6dbdSKonstantin Belousov ntsync_wait_link_waiters(struct ntsync_wait_state *state)
11803ca6dbdSKonstantin Belousov {
11903ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
12003ca6dbdSKonstantin Belousov struct ntsync_obj_waiter *waiter;
12103ca6dbdSKonstantin Belousov int i;
12203ca6dbdSKonstantin Belousov
12303ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(state->owner);
12403ca6dbdSKonstantin Belousov
12503ca6dbdSKonstantin Belousov for (i = 0; i < state->obj_count; i++) {
12603ca6dbdSKonstantin Belousov obj = state->objs[i];
12703ca6dbdSKonstantin Belousov waiter = &state->waiters[i];
12803ca6dbdSKonstantin Belousov waiter->state = state;
12903ca6dbdSKonstantin Belousov TAILQ_INSERT_TAIL(&obj->waiters, waiter, link);
13003ca6dbdSKonstantin Belousov }
13103ca6dbdSKonstantin Belousov }
13203ca6dbdSKonstantin Belousov
13303ca6dbdSKonstantin Belousov static void
ntsync_wait_unlink_waiters(struct ntsync_wait_state * state)13403ca6dbdSKonstantin Belousov ntsync_wait_unlink_waiters(struct ntsync_wait_state *state)
13503ca6dbdSKonstantin Belousov {
13603ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
13703ca6dbdSKonstantin Belousov struct ntsync_obj_waiter *waiter;
13803ca6dbdSKonstantin Belousov int i;
13903ca6dbdSKonstantin Belousov
14003ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(state->owner);
14103ca6dbdSKonstantin Belousov
14203ca6dbdSKonstantin Belousov for (i = 0; i < state->obj_count; i++) {
14303ca6dbdSKonstantin Belousov obj = state->objs[i];
14403ca6dbdSKonstantin Belousov waiter = &state->waiters[i];
14503ca6dbdSKonstantin Belousov TAILQ_REMOVE(&obj->waiters, waiter, link);
14603ca6dbdSKonstantin Belousov }
14703ca6dbdSKonstantin Belousov }
14803ca6dbdSKonstantin Belousov
14903ca6dbdSKonstantin Belousov static void
ntsync_wait_post_commit(struct ntsync_wait_state * state)15003ca6dbdSKonstantin Belousov ntsync_wait_post_commit(struct ntsync_wait_state *state)
15103ca6dbdSKonstantin Belousov {
15203ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
15303ca6dbdSKonstantin Belousov int alerti, i;
15403ca6dbdSKonstantin Belousov
15503ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(state->owner);
15603ca6dbdSKonstantin Belousov
15703ca6dbdSKonstantin Belousov alerti = state->alert_event == NULL ? 0 : 1;
15803ca6dbdSKonstantin Belousov for (i = 0; i < state->obj_count - alerti; i++) {
15903ca6dbdSKonstantin Belousov obj = state->objs[i];
16003ca6dbdSKonstantin Belousov obj->post_commit(obj, state, i);
16103ca6dbdSKonstantin Belousov }
16203ca6dbdSKonstantin Belousov }
16303ca6dbdSKonstantin Belousov
16403ca6dbdSKonstantin Belousov static void
ntsync_wait_check_ready(struct ntsync_wait_state * state)16503ca6dbdSKonstantin Belousov ntsync_wait_check_ready(struct ntsync_wait_state *state)
16603ca6dbdSKonstantin Belousov {
16703ca6dbdSKonstantin Belousov struct ntsync_obj *ae;
16803ca6dbdSKonstantin Belousov int index;
16903ca6dbdSKonstantin Belousov bool stop;
17003ca6dbdSKonstantin Belousov
17103ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(state->owner);
17203ca6dbdSKonstantin Belousov
17303ca6dbdSKonstantin Belousov if (state->ready)
17403ca6dbdSKonstantin Belousov return;
17503ca6dbdSKonstantin Belousov
17603ca6dbdSKonstantin Belousov if (state->all) {
17703ca6dbdSKonstantin Belousov stop = false;
17803ca6dbdSKonstantin Belousov if (ntsync_wait_all_prepare(state, &stop)) {
17903ca6dbdSKonstantin Belousov MPASS(!stop);
18003ca6dbdSKonstantin Belousov ntsync_wait_all_commit(state);
18103ca6dbdSKonstantin Belousov state->ready = true;
18203ca6dbdSKonstantin Belousov ntsync_wait_post_commit(state);
18303ca6dbdSKonstantin Belousov } else if (stop) {
18403ca6dbdSKonstantin Belousov /* skip */
18503ca6dbdSKonstantin Belousov } else if (state->alert_event != NULL) {
18603ca6dbdSKonstantin Belousov ae = &state->alert_event->obj;
18703ca6dbdSKonstantin Belousov index = state->obj_count - 1;
18803ca6dbdSKonstantin Belousov if (ae->is_signaled(ae, state, index)) {
18903ca6dbdSKonstantin Belousov state->index = index;
19003ca6dbdSKonstantin Belousov ae->consume(ae, state, index);
19103ca6dbdSKonstantin Belousov ae->post_commit(ae, state, index);
19203ca6dbdSKonstantin Belousov state->ready = true;
19303ca6dbdSKonstantin Belousov }
19403ca6dbdSKonstantin Belousov }
19503ca6dbdSKonstantin Belousov } else { /* state->any */
19603ca6dbdSKonstantin Belousov if (ntsync_wait_any(state))
19703ca6dbdSKonstantin Belousov state->ready = true;
19803ca6dbdSKonstantin Belousov }
19903ca6dbdSKonstantin Belousov }
20003ca6dbdSKonstantin Belousov
20103ca6dbdSKonstantin Belousov /*
20203ca6dbdSKonstantin Belousov * Perform the wait. Errors returned through state->error still
20303ca6dbdSKonstantin Belousov * result in the copyout of the ntsync_wait_args after the wait, while
20403ca6dbdSKonstantin Belousov * errors returned as the function result do not.
20503ca6dbdSKonstantin Belousov */
20603ca6dbdSKonstantin Belousov static int
ntsync_wait_locked(struct ntsync_wait_state * state,struct thread * td)20703ca6dbdSKonstantin Belousov ntsync_wait_locked(struct ntsync_wait_state *state, struct thread *td)
20803ca6dbdSKonstantin Belousov {
20903ca6dbdSKonstantin Belousov int error;
21003ca6dbdSKonstantin Belousov
21103ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(state->owner);
21203ca6dbdSKonstantin Belousov
21303ca6dbdSKonstantin Belousov for (;;) {
21403ca6dbdSKonstantin Belousov ntsync_wait_check_ready(state);
21503ca6dbdSKonstantin Belousov if (state->ready)
21603ca6dbdSKonstantin Belousov break;
21703ca6dbdSKonstantin Belousov error = msleep_sbt(state, &state->owner->lock,
21803ca6dbdSKonstantin Belousov PCATCH, "ntsync", state->sb, 0,
21903ca6dbdSKonstantin Belousov C_ABSOLUTE /* | C_HARDCLOCK XXXKIB */);
22003ca6dbdSKonstantin Belousov
22103ca6dbdSKonstantin Belousov /*
22203ca6dbdSKonstantin Belousov * Check state->ready before checking error from
22303ca6dbdSKonstantin Belousov * msleep(). If there was a wake up that set the
22403ca6dbdSKonstantin Belousov * readiness before us receiving a signal or timeout,
22503ca6dbdSKonstantin Belousov * the objects states are modified to reflect wakeup.
22603ca6dbdSKonstantin Belousov * Due to this, ready should result in normal return.
22703ca6dbdSKonstantin Belousov */
22803ca6dbdSKonstantin Belousov if (state->ready) {
22903ca6dbdSKonstantin Belousov error = 0;
23003ca6dbdSKonstantin Belousov break;
23103ca6dbdSKonstantin Belousov }
23203ca6dbdSKonstantin Belousov
23303ca6dbdSKonstantin Belousov if (error != 0) {
23403ca6dbdSKonstantin Belousov if (error == EAGAIN)
23503ca6dbdSKonstantin Belousov error = ETIMEDOUT;
23603ca6dbdSKonstantin Belousov break;
23703ca6dbdSKonstantin Belousov }
23803ca6dbdSKonstantin Belousov }
23903ca6dbdSKonstantin Belousov return (error);
24003ca6dbdSKonstantin Belousov }
24103ca6dbdSKonstantin Belousov
24203ca6dbdSKonstantin Belousov static int
ntsync_wait(struct ntsync_wait_state * state,struct thread * td)24303ca6dbdSKonstantin Belousov ntsync_wait(struct ntsync_wait_state *state, struct thread *td)
24403ca6dbdSKonstantin Belousov {
24503ca6dbdSKonstantin Belousov int error;
24603ca6dbdSKonstantin Belousov
24703ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(state->owner);
24803ca6dbdSKonstantin Belousov ntsync_wait_link_waiters(state);
24903ca6dbdSKonstantin Belousov error = ntsync_wait_locked(state, td);
25003ca6dbdSKonstantin Belousov ntsync_wait_unlink_waiters(state);
25103ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(state->owner);
25203ca6dbdSKonstantin Belousov return (error);
25303ca6dbdSKonstantin Belousov }
25403ca6dbdSKonstantin Belousov
25503ca6dbdSKonstantin Belousov static void
ntsync_wakeup_waiters(struct ntsync_obj * obj)25603ca6dbdSKonstantin Belousov ntsync_wakeup_waiters(struct ntsync_obj *obj)
25703ca6dbdSKonstantin Belousov {
25803ca6dbdSKonstantin Belousov struct ntsync_obj_waiter *w;
25903ca6dbdSKonstantin Belousov
26003ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner);
26103ca6dbdSKonstantin Belousov
26203ca6dbdSKonstantin Belousov TAILQ_FOREACH(w, &obj->waiters, link) {
26303ca6dbdSKonstantin Belousov ntsync_wait_check_ready(w->state);
26403ca6dbdSKonstantin Belousov if (w->state->ready)
26503ca6dbdSKonstantin Belousov wakeup(w->state);
26603ca6dbdSKonstantin Belousov }
26703ca6dbdSKonstantin Belousov }
26803ca6dbdSKonstantin Belousov
26903ca6dbdSKonstantin Belousov static int
ntsync_create_obj(struct ntsync_obj * obj,struct fileops * fops,struct ntsync_priv * priv,struct thread * td)27003ca6dbdSKonstantin Belousov ntsync_create_obj(struct ntsync_obj *obj, struct fileops *fops,
27103ca6dbdSKonstantin Belousov struct ntsync_priv *priv, struct thread *td)
27203ca6dbdSKonstantin Belousov {
27303ca6dbdSKonstantin Belousov struct file *fp;
27403ca6dbdSKonstantin Belousov int error, fd;
27503ca6dbdSKonstantin Belousov
27603ca6dbdSKonstantin Belousov error = falloc_noinstall(td, &fp);
27703ca6dbdSKonstantin Belousov if (error != 0)
27803ca6dbdSKonstantin Belousov return (error);
27903ca6dbdSKonstantin Belousov
28003ca6dbdSKonstantin Belousov /*
28103ca6dbdSKonstantin Belousov * The priv fd cannot be closed during object creation since
28203ca6dbdSKonstantin Belousov * it is fget-ed around ioctl.
28303ca6dbdSKonstantin Belousov */
28403ca6dbdSKonstantin Belousov obj->owner = priv;
28503ca6dbdSKonstantin Belousov
28603ca6dbdSKonstantin Belousov TAILQ_INIT(&obj->waiters);
28703ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv);
28803ca6dbdSKonstantin Belousov MPASS(!priv->closed);
28903ca6dbdSKonstantin Belousov if (priv->objs_cnt == UINT_MAX) {
29003ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv);
29103ca6dbdSKonstantin Belousov fdrop(fp, td);
29203ca6dbdSKonstantin Belousov return (EMFILE);
29303ca6dbdSKonstantin Belousov }
29403ca6dbdSKonstantin Belousov priv->objs_cnt++;
29503ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv);
29603ca6dbdSKonstantin Belousov
29703ca6dbdSKonstantin Belousov finit(fp, FREAD | FWRITE, DTYPE_NTSYNC, obj, fops);
29803ca6dbdSKonstantin Belousov error = finstall(td, fp, &fd, 0, NULL);
29903ca6dbdSKonstantin Belousov if (error != 0) {
30003ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv);
30103ca6dbdSKonstantin Belousov MPASS(priv->objs_cnt > 0);
30203ca6dbdSKonstantin Belousov priv->objs_cnt--;
30303ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv);
30403ca6dbdSKonstantin Belousov } else {
30503ca6dbdSKonstantin Belousov td->td_retval[0] = fd;
30603ca6dbdSKonstantin Belousov }
30703ca6dbdSKonstantin Belousov fdrop(fp, td);
30803ca6dbdSKonstantin Belousov return (error);
30903ca6dbdSKonstantin Belousov }
31003ca6dbdSKonstantin Belousov
31103ca6dbdSKonstantin Belousov static void
ntsync_close_obj(struct ntsync_obj * obj,struct thread * td)31203ca6dbdSKonstantin Belousov ntsync_close_obj(struct ntsync_obj *obj, struct thread *td)
31303ca6dbdSKonstantin Belousov {
31403ca6dbdSKonstantin Belousov struct ntsync_priv *priv;
31503ca6dbdSKonstantin Belousov
31603ca6dbdSKonstantin Belousov priv = obj->owner;
31703ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv);
31803ca6dbdSKonstantin Belousov MPASS(priv->objs_cnt > 0);
31903ca6dbdSKonstantin Belousov MPASS(TAILQ_EMPTY(&obj->waiters));
32003ca6dbdSKonstantin Belousov priv->objs_cnt--;
32103ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv);
32203ca6dbdSKonstantin Belousov ntsync_free_priv(priv);
32303ca6dbdSKonstantin Belousov }
32403ca6dbdSKonstantin Belousov
32503ca6dbdSKonstantin Belousov static bool
ntsync_sem_is_signaled(struct ntsync_obj * obj,struct ntsync_wait_state * state,int index)32603ca6dbdSKonstantin Belousov ntsync_sem_is_signaled(struct ntsync_obj *obj, struct ntsync_wait_state *state,
32703ca6dbdSKonstantin Belousov int index)
32803ca6dbdSKonstantin Belousov {
32903ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem;
33003ca6dbdSKonstantin Belousov
33103ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_SEM);
33203ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner);
33303ca6dbdSKonstantin Belousov sem = OBJ_TO_SEM(obj);
33403ca6dbdSKonstantin Belousov return (sem->a.count != 0);
33503ca6dbdSKonstantin Belousov }
33603ca6dbdSKonstantin Belousov
33703ca6dbdSKonstantin Belousov static void
ntsync_sem_consume(struct ntsync_obj * obj,struct ntsync_wait_state * state,int index)33803ca6dbdSKonstantin Belousov ntsync_sem_consume(struct ntsync_obj *obj, struct ntsync_wait_state *state,
33903ca6dbdSKonstantin Belousov int index)
34003ca6dbdSKonstantin Belousov {
34103ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem;
34203ca6dbdSKonstantin Belousov
34303ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_SEM);
34403ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner);
34503ca6dbdSKonstantin Belousov sem = OBJ_TO_SEM(obj);
34603ca6dbdSKonstantin Belousov MPASS(sem->a.count != 0);
34703ca6dbdSKonstantin Belousov sem->a.count--;
34803ca6dbdSKonstantin Belousov }
34903ca6dbdSKonstantin Belousov
35003ca6dbdSKonstantin Belousov static bool
ntsync_sem_prepare(struct ntsync_obj * obj,struct ntsync_wait_state * state,int index,bool * stop)35103ca6dbdSKonstantin Belousov ntsync_sem_prepare(struct ntsync_obj *obj, struct ntsync_wait_state *state,
35203ca6dbdSKonstantin Belousov int index, bool *stop)
35303ca6dbdSKonstantin Belousov {
35403ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem;
35503ca6dbdSKonstantin Belousov
35603ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_SEM);
35703ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner);
35803ca6dbdSKonstantin Belousov sem = OBJ_TO_SEM(obj);
35903ca6dbdSKonstantin Belousov if (sem->a.count == 0)
36003ca6dbdSKonstantin Belousov return (false);
36103ca6dbdSKonstantin Belousov sem->a1 = sem->a;
36203ca6dbdSKonstantin Belousov sem->a1.count--;
36303ca6dbdSKonstantin Belousov return (true);
36403ca6dbdSKonstantin Belousov }
36503ca6dbdSKonstantin Belousov
36603ca6dbdSKonstantin Belousov static void
ntsync_sem_commit(struct ntsync_obj * obj,struct ntsync_wait_state * state,int index)36703ca6dbdSKonstantin Belousov ntsync_sem_commit(struct ntsync_obj *obj, struct ntsync_wait_state *state,
36803ca6dbdSKonstantin Belousov int index)
36903ca6dbdSKonstantin Belousov {
37003ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem;
37103ca6dbdSKonstantin Belousov
37203ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_SEM);
37303ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner);
37403ca6dbdSKonstantin Belousov sem = OBJ_TO_SEM(obj);
37503ca6dbdSKonstantin Belousov sem->a = sem->a1;
37603ca6dbdSKonstantin Belousov }
37703ca6dbdSKonstantin Belousov
37803ca6dbdSKonstantin Belousov static void
ntsync_sem_post_commit(struct ntsync_obj * obj,struct ntsync_wait_state * state,int index)37903ca6dbdSKonstantin Belousov ntsync_sem_post_commit(struct ntsync_obj *obj, struct ntsync_wait_state *state,
38003ca6dbdSKonstantin Belousov int index)
38103ca6dbdSKonstantin Belousov {
38203ca6dbdSKonstantin Belousov }
38303ca6dbdSKonstantin Belousov
38403ca6dbdSKonstantin Belousov static int
ntsync_sem_close(struct file * fp,struct thread * td)38503ca6dbdSKonstantin Belousov ntsync_sem_close(struct file *fp, struct thread *td)
38603ca6dbdSKonstantin Belousov {
38703ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem;
38803ca6dbdSKonstantin Belousov
38903ca6dbdSKonstantin Belousov sem = fp->f_data;
39003ca6dbdSKonstantin Belousov ntsync_close_obj(&sem->obj, td);
39103ca6dbdSKonstantin Belousov free(sem, M_NTSYNC);
39203ca6dbdSKonstantin Belousov return (0);
39303ca6dbdSKonstantin Belousov }
39403ca6dbdSKonstantin Belousov
39503ca6dbdSKonstantin Belousov int
ntsync_sem_release(struct thread * td,struct file * fp,uint32_t * val)39603ca6dbdSKonstantin Belousov ntsync_sem_release(struct thread *td, struct file *fp, uint32_t *val)
39703ca6dbdSKonstantin Belousov {
39803ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
39903ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem;
40003ca6dbdSKonstantin Belousov struct ntsync_priv *priv;
40103ca6dbdSKonstantin Belousov uint32_t prev;
40203ca6dbdSKonstantin Belousov int error;
40303ca6dbdSKonstantin Belousov
40403ca6dbdSKonstantin Belousov obj = fp->f_data;
40503ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_SEM)
40603ca6dbdSKonstantin Belousov return (EINVAL);
40703ca6dbdSKonstantin Belousov sem = OBJ_TO_SEM(obj);
40803ca6dbdSKonstantin Belousov priv = obj->owner;
40903ca6dbdSKonstantin Belousov error = 0;
41003ca6dbdSKonstantin Belousov
41103ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv);
41203ca6dbdSKonstantin Belousov if (sem->a.count + *val < sem->a.count ||
41303ca6dbdSKonstantin Belousov sem->a.count + *val > sem->a.max) {
41403ca6dbdSKonstantin Belousov error = EOVERFLOW;
41503ca6dbdSKonstantin Belousov } else {
41603ca6dbdSKonstantin Belousov prev = sem->a.count;
41703ca6dbdSKonstantin Belousov sem->a.count += *val;
41803ca6dbdSKonstantin Belousov if (sem->a.count != 0)
41903ca6dbdSKonstantin Belousov ntsync_wakeup_waiters(obj);
42003ca6dbdSKonstantin Belousov *val = prev;
42103ca6dbdSKonstantin Belousov }
42203ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv);
42303ca6dbdSKonstantin Belousov return (error);
42403ca6dbdSKonstantin Belousov }
42503ca6dbdSKonstantin Belousov
42603ca6dbdSKonstantin Belousov int
ntsync_sem_read(struct thread * td,struct file * fp,struct ntsync_sem_args * a)42703ca6dbdSKonstantin Belousov ntsync_sem_read(struct thread *td, struct file *fp, struct ntsync_sem_args *a)
42803ca6dbdSKonstantin Belousov {
42903ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
43003ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem;
43103ca6dbdSKonstantin Belousov struct ntsync_priv *priv;
43203ca6dbdSKonstantin Belousov
43303ca6dbdSKonstantin Belousov obj = fp->f_data;
43403ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_SEM)
43503ca6dbdSKonstantin Belousov return (EINVAL);
43603ca6dbdSKonstantin Belousov sem = OBJ_TO_SEM(obj);
43703ca6dbdSKonstantin Belousov priv = obj->owner;
43803ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv);
43903ca6dbdSKonstantin Belousov *a = sem->a;
44003ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv);
44103ca6dbdSKonstantin Belousov return (0);
44203ca6dbdSKonstantin Belousov }
44303ca6dbdSKonstantin Belousov
44403ca6dbdSKonstantin Belousov static int
ntsync_sem_ioctl(struct file * fp,u_long com,void * data,struct ucred * active_cred,struct thread * td)44503ca6dbdSKonstantin Belousov ntsync_sem_ioctl(struct file *fp, u_long com, void *data,
44603ca6dbdSKonstantin Belousov struct ucred *active_cred, struct thread *td)
44703ca6dbdSKonstantin Belousov {
44803ca6dbdSKonstantin Belousov int error;
44903ca6dbdSKonstantin Belousov
45003ca6dbdSKonstantin Belousov switch (com) {
45103ca6dbdSKonstantin Belousov case NTSYNC_IOC_SEM_RELEASE:
45203ca6dbdSKonstantin Belousov error = ntsync_sem_release(td, fp, data);
45303ca6dbdSKonstantin Belousov break;
45403ca6dbdSKonstantin Belousov case NTSYNC_IOC_SEM_READ:
45503ca6dbdSKonstantin Belousov error = ntsync_sem_read(td, fp, data);
45603ca6dbdSKonstantin Belousov break;
45703ca6dbdSKonstantin Belousov default:
45803ca6dbdSKonstantin Belousov error = ENOTTY;
45903ca6dbdSKonstantin Belousov break;
46003ca6dbdSKonstantin Belousov }
46103ca6dbdSKonstantin Belousov return (error);
46203ca6dbdSKonstantin Belousov }
46303ca6dbdSKonstantin Belousov
46403ca6dbdSKonstantin Belousov static int
ntsync_sem_stat(struct file * fp,struct stat * sbp,struct ucred * cred)46503ca6dbdSKonstantin Belousov ntsync_sem_stat(struct file *fp, struct stat *sbp, struct ucred *cred)
46603ca6dbdSKonstantin Belousov {
46703ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
46803ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem;
46903ca6dbdSKonstantin Belousov
47003ca6dbdSKonstantin Belousov MPASS(fp->f_type == DTYPE_NTSYNC);
47103ca6dbdSKonstantin Belousov obj = fp->f_data;
47203ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_SEM);
47303ca6dbdSKonstantin Belousov sem = OBJ_TO_SEM(obj);
47403ca6dbdSKonstantin Belousov
47503ca6dbdSKonstantin Belousov memset(sbp, 0, sizeof(*sbp));
47603ca6dbdSKonstantin Belousov sbp->st_mode = S_IFREG /* XXXKIB */ | S_IRUSR | S_IWUSR;
47703ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(obj->owner);
47803ca6dbdSKonstantin Belousov sbp->st_size = sem->a.max;
47903ca6dbdSKonstantin Belousov sbp->st_nlink = sem->a.count;
48003ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(obj->owner);
48103ca6dbdSKonstantin Belousov return (0);
48203ca6dbdSKonstantin Belousov }
48303ca6dbdSKonstantin Belousov
48403ca6dbdSKonstantin Belousov static int
ntsync_sem_fill_kinfo(struct file * fp,struct kinfo_file * kif,struct filedesc * fdp)48503ca6dbdSKonstantin Belousov ntsync_sem_fill_kinfo(struct file *fp, struct kinfo_file *kif,
48603ca6dbdSKonstantin Belousov struct filedesc *fdp)
48703ca6dbdSKonstantin Belousov {
488*d0ea3affSKonstantin Belousov struct ntsync_obj *obj;
489*d0ea3affSKonstantin Belousov struct ntsync_obj_sem *sem;
490*d0ea3affSKonstantin Belousov
491*d0ea3affSKonstantin Belousov MPASS(fp->f_type == DTYPE_NTSYNC);
492*d0ea3affSKonstantin Belousov obj = fp->f_data;
493*d0ea3affSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_SEM);
494*d0ea3affSKonstantin Belousov sem = OBJ_TO_SEM(obj);
495*d0ea3affSKonstantin Belousov
496*d0ea3affSKonstantin Belousov kif->kf_type = KF_TYPE_NTSYNC;
497*d0ea3affSKonstantin Belousov kif->kf_un.kf_ntsync.kf_ntsync_type = KF_NTSYNC_TYPE_SEM;
498*d0ea3affSKonstantin Belousov kif->kf_un.kf_ntsync.kf_ntsync_dev = (uintptr_t)obj->owner;
499*d0ea3affSKonstantin Belousov kif->kf_un.kf_ntsync.kf_ntsync_un.kf_ntsync_sem.count = sem->a.count;
500*d0ea3affSKonstantin Belousov kif->kf_un.kf_ntsync.kf_ntsync_un.kf_ntsync_sem.max = sem->a.max;
50103ca6dbdSKonstantin Belousov return (0);
50203ca6dbdSKonstantin Belousov }
50303ca6dbdSKonstantin Belousov
50403ca6dbdSKonstantin Belousov struct fileops ntsync_sem_fops = {
50503ca6dbdSKonstantin Belousov .fo_read = invfo_rdwr,
50603ca6dbdSKonstantin Belousov .fo_write = invfo_rdwr,
50703ca6dbdSKonstantin Belousov .fo_truncate = invfo_truncate,
50803ca6dbdSKonstantin Belousov .fo_ioctl = ntsync_sem_ioctl,
50903ca6dbdSKonstantin Belousov .fo_poll = invfo_poll,
51003ca6dbdSKonstantin Belousov .fo_kqfilter = invfo_kqfilter,
51103ca6dbdSKonstantin Belousov .fo_stat = ntsync_sem_stat,
51203ca6dbdSKonstantin Belousov .fo_close = ntsync_sem_close,
51303ca6dbdSKonstantin Belousov .fo_chmod = invfo_chmod,
51403ca6dbdSKonstantin Belousov .fo_chown = invfo_chown,
51503ca6dbdSKonstantin Belousov .fo_sendfile = invfo_sendfile,
51603ca6dbdSKonstantin Belousov .fo_fill_kinfo = ntsync_sem_fill_kinfo,
51703ca6dbdSKonstantin Belousov .fo_flags = DFLAG_PASSABLE,
51803ca6dbdSKonstantin Belousov };
51903ca6dbdSKonstantin Belousov
52003ca6dbdSKonstantin Belousov static int
ntsync_create_sem(struct ntsync_sem_args * args,struct ntsync_priv * priv,struct thread * td)52103ca6dbdSKonstantin Belousov ntsync_create_sem(struct ntsync_sem_args *args, struct ntsync_priv *priv,
52203ca6dbdSKonstantin Belousov struct thread *td)
52303ca6dbdSKonstantin Belousov {
52403ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem;
52503ca6dbdSKonstantin Belousov int error;
52603ca6dbdSKonstantin Belousov
52703ca6dbdSKonstantin Belousov if (args->count > args->max)
52803ca6dbdSKonstantin Belousov return (EINVAL);
52903ca6dbdSKonstantin Belousov
53003ca6dbdSKonstantin Belousov sem = malloc(sizeof(*sem), M_NTSYNC, M_WAITOK | M_ZERO);
53103ca6dbdSKonstantin Belousov sem->obj.type = NTSYNC_OBJ_SEM;
53203ca6dbdSKonstantin Belousov sem->obj.is_signaled = ntsync_sem_is_signaled;
53303ca6dbdSKonstantin Belousov sem->obj.consume = ntsync_sem_consume;
53403ca6dbdSKonstantin Belousov sem->obj.prepare = ntsync_sem_prepare;
53503ca6dbdSKonstantin Belousov sem->obj.commit = ntsync_sem_commit;
53603ca6dbdSKonstantin Belousov sem->obj.post_commit = ntsync_sem_post_commit;
53703ca6dbdSKonstantin Belousov sem->a = *args;
53803ca6dbdSKonstantin Belousov
53903ca6dbdSKonstantin Belousov error = ntsync_create_obj(&sem->obj, &ntsync_sem_fops, priv, td);
54003ca6dbdSKonstantin Belousov if (error != 0)
54103ca6dbdSKonstantin Belousov free(sem, M_NTSYNC);
54203ca6dbdSKonstantin Belousov
54303ca6dbdSKonstantin Belousov return (error);
54403ca6dbdSKonstantin Belousov }
54503ca6dbdSKonstantin Belousov
54603ca6dbdSKonstantin Belousov static bool
ntsync_mutex_can_lock(struct ntsync_obj_mutex * mutex,uint32_t nwa_owner)54703ca6dbdSKonstantin Belousov ntsync_mutex_can_lock(struct ntsync_obj_mutex *mutex, uint32_t nwa_owner)
54803ca6dbdSKonstantin Belousov {
54903ca6dbdSKonstantin Belousov return (mutex->a.owner == 0 ||
55003ca6dbdSKonstantin Belousov (mutex->a.owner == nwa_owner && mutex->a.count < UINT32_MAX) ||
55103ca6dbdSKonstantin Belousov mutex->abandoned);
55203ca6dbdSKonstantin Belousov }
55303ca6dbdSKonstantin Belousov
55403ca6dbdSKonstantin Belousov static bool
ntsync_mutex_is_signaled(struct ntsync_obj * obj,struct ntsync_wait_state * state,int index)55503ca6dbdSKonstantin Belousov ntsync_mutex_is_signaled(struct ntsync_obj *obj,
55603ca6dbdSKonstantin Belousov struct ntsync_wait_state *state, int index)
55703ca6dbdSKonstantin Belousov {
55803ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex;
55903ca6dbdSKonstantin Belousov
56003ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_MUTEX);
56103ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner);
56203ca6dbdSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj);
56303ca6dbdSKonstantin Belousov return (ntsync_mutex_can_lock(mutex, state->nwa->owner));
56403ca6dbdSKonstantin Belousov }
56503ca6dbdSKonstantin Belousov
56603ca6dbdSKonstantin Belousov static void
ntsync_mutex_consume(struct ntsync_obj * obj,struct ntsync_wait_state * state,int index)56703ca6dbdSKonstantin Belousov ntsync_mutex_consume(struct ntsync_obj *obj, struct ntsync_wait_state *state,
56803ca6dbdSKonstantin Belousov int index)
56903ca6dbdSKonstantin Belousov {
57003ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex;
57103ca6dbdSKonstantin Belousov
57203ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_MUTEX);
57303ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner);
57403ca6dbdSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj);
57503ca6dbdSKonstantin Belousov MPASS(ntsync_mutex_can_lock(mutex, state->nwa->owner));
57603ca6dbdSKonstantin Belousov if (state->nwa->owner == 0) {
57703ca6dbdSKonstantin Belousov state->error = EINVAL;
57803ca6dbdSKonstantin Belousov return;
57903ca6dbdSKonstantin Belousov }
58003ca6dbdSKonstantin Belousov if (mutex->a.owner == 0 || mutex->abandoned)
58103ca6dbdSKonstantin Belousov mutex->a.count = 1;
58203ca6dbdSKonstantin Belousov else
58303ca6dbdSKonstantin Belousov mutex->a.count++;
58403ca6dbdSKonstantin Belousov mutex->a.owner = state->nwa->owner;
58503ca6dbdSKonstantin Belousov if (mutex->abandoned && state->error == 0)
58603ca6dbdSKonstantin Belousov state->error = EOWNERDEAD;
58703ca6dbdSKonstantin Belousov mutex->abandoned = false;
58803ca6dbdSKonstantin Belousov }
58903ca6dbdSKonstantin Belousov
59003ca6dbdSKonstantin Belousov static bool
ntsync_mutex_prepare(struct ntsync_obj * obj,struct ntsync_wait_state * state,int index,bool * stop)59103ca6dbdSKonstantin Belousov ntsync_mutex_prepare(struct ntsync_obj *obj, struct ntsync_wait_state *state,
59203ca6dbdSKonstantin Belousov int index, bool *stop)
59303ca6dbdSKonstantin Belousov {
59403ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex;
59503ca6dbdSKonstantin Belousov
59603ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_MUTEX);
59703ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner);
59803ca6dbdSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj);
59903ca6dbdSKonstantin Belousov if (!ntsync_mutex_can_lock(mutex, state->nwa->owner))
60003ca6dbdSKonstantin Belousov return (false);
60103ca6dbdSKonstantin Belousov if (state->nwa->owner == 0) {
60203ca6dbdSKonstantin Belousov state->error = EINVAL;
60303ca6dbdSKonstantin Belousov *stop = true;
60403ca6dbdSKonstantin Belousov return (false);
60503ca6dbdSKonstantin Belousov }
60603ca6dbdSKonstantin Belousov mutex->a1 = mutex->a;
60703ca6dbdSKonstantin Belousov if (mutex->a.owner == 0 || mutex->abandoned)
60803ca6dbdSKonstantin Belousov mutex->a1.count = 1;
60903ca6dbdSKonstantin Belousov else
61003ca6dbdSKonstantin Belousov mutex->a1.count++;
61103ca6dbdSKonstantin Belousov mutex->a1.owner = state->nwa->owner;
61203ca6dbdSKonstantin Belousov return (true);
61303ca6dbdSKonstantin Belousov }
61403ca6dbdSKonstantin Belousov
61503ca6dbdSKonstantin Belousov static void
ntsync_mutex_commit(struct ntsync_obj * obj,struct ntsync_wait_state * state,int index)61603ca6dbdSKonstantin Belousov ntsync_mutex_commit(struct ntsync_obj *obj, struct ntsync_wait_state *state,
61703ca6dbdSKonstantin Belousov int index)
61803ca6dbdSKonstantin Belousov {
61903ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex;
62003ca6dbdSKonstantin Belousov
62103ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_MUTEX);
62203ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner);
62303ca6dbdSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj);
62403ca6dbdSKonstantin Belousov mutex->a = mutex->a1;
62503ca6dbdSKonstantin Belousov if (mutex->abandoned)
62603ca6dbdSKonstantin Belousov state->error = EOWNERDEAD;
62703ca6dbdSKonstantin Belousov mutex->abandoned = false;
62803ca6dbdSKonstantin Belousov }
62903ca6dbdSKonstantin Belousov
63003ca6dbdSKonstantin Belousov static void
ntsync_mutex_post_commit(struct ntsync_obj * obj,struct ntsync_wait_state * state,int index)63103ca6dbdSKonstantin Belousov ntsync_mutex_post_commit(struct ntsync_obj *obj,
63203ca6dbdSKonstantin Belousov struct ntsync_wait_state *state, int index)
63303ca6dbdSKonstantin Belousov {
63403ca6dbdSKonstantin Belousov }
63503ca6dbdSKonstantin Belousov
63603ca6dbdSKonstantin Belousov static int
ntsync_mutex_close(struct file * fp,struct thread * td)63703ca6dbdSKonstantin Belousov ntsync_mutex_close(struct file *fp, struct thread *td)
63803ca6dbdSKonstantin Belousov {
63903ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex;
64003ca6dbdSKonstantin Belousov
64103ca6dbdSKonstantin Belousov mutex = fp->f_data;
64203ca6dbdSKonstantin Belousov ntsync_close_obj(&mutex->obj, td);
64303ca6dbdSKonstantin Belousov free(mutex, M_NTSYNC);
64403ca6dbdSKonstantin Belousov return (0);
64503ca6dbdSKonstantin Belousov }
64603ca6dbdSKonstantin Belousov
64703ca6dbdSKonstantin Belousov int
ntsync_mutex_unlock(struct thread * td,struct file * fp,struct ntsync_mutex_args * a)64803ca6dbdSKonstantin Belousov ntsync_mutex_unlock(struct thread *td, struct file *fp,
64903ca6dbdSKonstantin Belousov struct ntsync_mutex_args *a)
65003ca6dbdSKonstantin Belousov {
65103ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
65203ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex;
65303ca6dbdSKonstantin Belousov struct ntsync_priv *priv;
65403ca6dbdSKonstantin Belousov uint32_t prev;
65503ca6dbdSKonstantin Belousov int error;
65603ca6dbdSKonstantin Belousov
65703ca6dbdSKonstantin Belousov obj = fp->f_data;
65803ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_MUTEX)
65903ca6dbdSKonstantin Belousov return (EINVAL);
66003ca6dbdSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj);
66103ca6dbdSKonstantin Belousov priv = obj->owner;
66203ca6dbdSKonstantin Belousov
66303ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv);
66403ca6dbdSKonstantin Belousov if (a->owner == 0) {
66503ca6dbdSKonstantin Belousov error = EINVAL;
66603ca6dbdSKonstantin Belousov } else if (a->owner != mutex->a.owner) {
66703ca6dbdSKonstantin Belousov error = EPERM;
66803ca6dbdSKonstantin Belousov } else {
66903ca6dbdSKonstantin Belousov error = 0;
67003ca6dbdSKonstantin Belousov prev = mutex->a.count;
67103ca6dbdSKonstantin Belousov MPASS(mutex->a.count > 0);
67203ca6dbdSKonstantin Belousov mutex->a.count--;
67303ca6dbdSKonstantin Belousov a->count = prev;
67403ca6dbdSKonstantin Belousov if (mutex->a.count == 0) {
67503ca6dbdSKonstantin Belousov mutex->a.owner = 0;
67603ca6dbdSKonstantin Belousov ntsync_wakeup_waiters(obj);
67703ca6dbdSKonstantin Belousov }
67803ca6dbdSKonstantin Belousov }
67903ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv);
68003ca6dbdSKonstantin Belousov return (error);
68103ca6dbdSKonstantin Belousov }
68203ca6dbdSKonstantin Belousov
68303ca6dbdSKonstantin Belousov int
ntsync_mutex_kill(struct thread * td,struct file * fp,uint32_t val)68403ca6dbdSKonstantin Belousov ntsync_mutex_kill(struct thread *td, struct file *fp, uint32_t val)
68503ca6dbdSKonstantin Belousov {
68603ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
68703ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex;
68803ca6dbdSKonstantin Belousov struct ntsync_priv *priv;
68903ca6dbdSKonstantin Belousov int error;
69003ca6dbdSKonstantin Belousov
69103ca6dbdSKonstantin Belousov obj = fp->f_data;
69203ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_MUTEX)
69303ca6dbdSKonstantin Belousov return (EINVAL);
69403ca6dbdSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj);
69503ca6dbdSKonstantin Belousov priv = obj->owner;
69603ca6dbdSKonstantin Belousov
69703ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv);
69803ca6dbdSKonstantin Belousov if (val == 0) {
69903ca6dbdSKonstantin Belousov error = EINVAL;
70003ca6dbdSKonstantin Belousov } else if (mutex->a.owner != val) {
70103ca6dbdSKonstantin Belousov error = EPERM;
70203ca6dbdSKonstantin Belousov } else {
70303ca6dbdSKonstantin Belousov error = 0;
70403ca6dbdSKonstantin Belousov mutex->a.owner = 0;
70503ca6dbdSKonstantin Belousov mutex->a.count = 0;
70603ca6dbdSKonstantin Belousov mutex->abandoned = true;
70703ca6dbdSKonstantin Belousov ntsync_wakeup_waiters(obj);
70803ca6dbdSKonstantin Belousov }
70903ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv);
71003ca6dbdSKonstantin Belousov return (error);
71103ca6dbdSKonstantin Belousov }
71203ca6dbdSKonstantin Belousov
71303ca6dbdSKonstantin Belousov int
ntsync_mutex_read(struct thread * td,struct file * fp,struct ntsync_mutex_args * a,bool * doco)71403ca6dbdSKonstantin Belousov ntsync_mutex_read(struct thread *td, struct file *fp,
71503ca6dbdSKonstantin Belousov struct ntsync_mutex_args *a, bool *doco)
71603ca6dbdSKonstantin Belousov {
71703ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
71803ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex;
71903ca6dbdSKonstantin Belousov struct ntsync_priv *priv;
72003ca6dbdSKonstantin Belousov int error;
72103ca6dbdSKonstantin Belousov
72203ca6dbdSKonstantin Belousov *doco = false;
72303ca6dbdSKonstantin Belousov obj = fp->f_data;
72403ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_MUTEX)
72503ca6dbdSKonstantin Belousov return (EINVAL);
72603ca6dbdSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj);
72703ca6dbdSKonstantin Belousov priv = obj->owner;
72803ca6dbdSKonstantin Belousov error = 0;
72903ca6dbdSKonstantin Belousov
73003ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv);
73103ca6dbdSKonstantin Belousov *a = mutex->a;
73203ca6dbdSKonstantin Belousov if (mutex->abandoned)
73303ca6dbdSKonstantin Belousov error = EOWNERDEAD;
73403ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv);
73503ca6dbdSKonstantin Belousov *doco = true;
73603ca6dbdSKonstantin Belousov return (error);
73703ca6dbdSKonstantin Belousov }
73803ca6dbdSKonstantin Belousov
73903ca6dbdSKonstantin Belousov static int
ntsync_mutex_ioctl(struct file * fp,u_long com,void * data,struct ucred * active_cred,struct thread * td)74003ca6dbdSKonstantin Belousov ntsync_mutex_ioctl(struct file *fp, u_long com, void *data,
74103ca6dbdSKonstantin Belousov struct ucred *active_cred, struct thread *td)
74203ca6dbdSKonstantin Belousov {
74303ca6dbdSKonstantin Belousov struct ntsync_mutex_args aa;
74403ca6dbdSKonstantin Belousov int error, error1;
74503ca6dbdSKonstantin Belousov bool doco;
74603ca6dbdSKonstantin Belousov
74703ca6dbdSKonstantin Belousov doco = false;
74803ca6dbdSKonstantin Belousov switch (com) {
74903ca6dbdSKonstantin Belousov case NTSYNC_IOC_MUTEX_UNLOCK:
75003ca6dbdSKonstantin Belousov error = ntsync_mutex_unlock(td, fp, data);
75103ca6dbdSKonstantin Belousov break;
75203ca6dbdSKonstantin Belousov case NTSYNC_IOC_MUTEX_KILL:
75303ca6dbdSKonstantin Belousov error = ntsync_mutex_kill(td, fp, *(uint32_t *)data);
75403ca6dbdSKonstantin Belousov break;
75503ca6dbdSKonstantin Belousov case NTSYNC_IOC_MUTEX_READ:
75603ca6dbdSKonstantin Belousov error = ntsync_mutex_read(td, fp, &aa, &doco);
75703ca6dbdSKonstantin Belousov if (doco) {
75803ca6dbdSKonstantin Belousov error1 = ntsync_ioctl_copyout(td, &aa, sizeof(aa));
75903ca6dbdSKonstantin Belousov if (error1 != 0)
76003ca6dbdSKonstantin Belousov error = error1;
76103ca6dbdSKonstantin Belousov }
76203ca6dbdSKonstantin Belousov break;
76303ca6dbdSKonstantin Belousov default:
76403ca6dbdSKonstantin Belousov error = ENOTTY;
76503ca6dbdSKonstantin Belousov break;
76603ca6dbdSKonstantin Belousov }
76703ca6dbdSKonstantin Belousov return (error);
76803ca6dbdSKonstantin Belousov }
76903ca6dbdSKonstantin Belousov
77003ca6dbdSKonstantin Belousov static int
ntsync_mutex_stat(struct file * fp,struct stat * sbp,struct ucred * cred)77103ca6dbdSKonstantin Belousov ntsync_mutex_stat(struct file *fp, struct stat *sbp, struct ucred *cred)
77203ca6dbdSKonstantin Belousov {
77303ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
77403ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex;
77503ca6dbdSKonstantin Belousov
77603ca6dbdSKonstantin Belousov MPASS(fp->f_type == DTYPE_NTSYNC);
77703ca6dbdSKonstantin Belousov obj = fp->f_data;
77803ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_MUTEX);
77903ca6dbdSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj);
78003ca6dbdSKonstantin Belousov
78103ca6dbdSKonstantin Belousov memset(sbp, 0, sizeof(*sbp));
78203ca6dbdSKonstantin Belousov sbp->st_mode = S_IFREG /* XXXKIB */ | S_IRUSR | S_IWUSR;
78303ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(obj->owner);
78403ca6dbdSKonstantin Belousov sbp->st_size = mutex->a.owner;
78503ca6dbdSKonstantin Belousov sbp->st_nlink = mutex->a.count;
78603ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(obj->owner);
78703ca6dbdSKonstantin Belousov return (0);
78803ca6dbdSKonstantin Belousov }
78903ca6dbdSKonstantin Belousov
79003ca6dbdSKonstantin Belousov static int
ntsync_mutex_fill_kinfo(struct file * fp,struct kinfo_file * kif,struct filedesc * fdp)79103ca6dbdSKonstantin Belousov ntsync_mutex_fill_kinfo(struct file *fp, struct kinfo_file *kif,
79203ca6dbdSKonstantin Belousov struct filedesc *fdp)
79303ca6dbdSKonstantin Belousov {
794*d0ea3affSKonstantin Belousov struct ntsync_obj *obj;
795*d0ea3affSKonstantin Belousov struct ntsync_obj_mutex *mutex;
796*d0ea3affSKonstantin Belousov
797*d0ea3affSKonstantin Belousov MPASS(fp->f_type == DTYPE_NTSYNC);
798*d0ea3affSKonstantin Belousov obj = fp->f_data;
799*d0ea3affSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_MUTEX);
800*d0ea3affSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj);
801*d0ea3affSKonstantin Belousov
802*d0ea3affSKonstantin Belousov kif->kf_type = KF_TYPE_NTSYNC;
803*d0ea3affSKonstantin Belousov kif->kf_un.kf_ntsync.kf_ntsync_type = KF_NTSYNC_TYPE_MUTEX;
804*d0ea3affSKonstantin Belousov kif->kf_un.kf_ntsync.kf_ntsync_dev = (uintptr_t)obj->owner;
805*d0ea3affSKonstantin Belousov kif->kf_un.kf_ntsync.kf_ntsync_un.kf_ntsync_mutex.owner =
806*d0ea3affSKonstantin Belousov mutex->a.owner;
807*d0ea3affSKonstantin Belousov kif->kf_un.kf_ntsync.kf_ntsync_un.kf_ntsync_mutex.count =
808*d0ea3affSKonstantin Belousov mutex->a.count;
80903ca6dbdSKonstantin Belousov return (0);
81003ca6dbdSKonstantin Belousov }
81103ca6dbdSKonstantin Belousov
81203ca6dbdSKonstantin Belousov struct fileops ntsync_mutex_fops = {
81303ca6dbdSKonstantin Belousov .fo_read = invfo_rdwr,
81403ca6dbdSKonstantin Belousov .fo_write = invfo_rdwr,
81503ca6dbdSKonstantin Belousov .fo_truncate = invfo_truncate,
81603ca6dbdSKonstantin Belousov .fo_ioctl = ntsync_mutex_ioctl,
81703ca6dbdSKonstantin Belousov .fo_poll = invfo_poll,
81803ca6dbdSKonstantin Belousov .fo_kqfilter = invfo_kqfilter,
81903ca6dbdSKonstantin Belousov .fo_stat = ntsync_mutex_stat,
82003ca6dbdSKonstantin Belousov .fo_close = ntsync_mutex_close,
82103ca6dbdSKonstantin Belousov .fo_chmod = invfo_chmod,
82203ca6dbdSKonstantin Belousov .fo_chown = invfo_chown,
82303ca6dbdSKonstantin Belousov .fo_sendfile = invfo_sendfile,
82403ca6dbdSKonstantin Belousov .fo_fill_kinfo = ntsync_mutex_fill_kinfo,
82503ca6dbdSKonstantin Belousov .fo_flags = DFLAG_PASSABLE,
82603ca6dbdSKonstantin Belousov };
82703ca6dbdSKonstantin Belousov
82803ca6dbdSKonstantin Belousov static int
ntsync_create_mutex(struct ntsync_mutex_args * args,struct ntsync_priv * priv,struct thread * td)82903ca6dbdSKonstantin Belousov ntsync_create_mutex(struct ntsync_mutex_args *args, struct ntsync_priv *priv,
83003ca6dbdSKonstantin Belousov struct thread *td)
83103ca6dbdSKonstantin Belousov {
83203ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex;
83303ca6dbdSKonstantin Belousov int error;
83403ca6dbdSKonstantin Belousov
83503ca6dbdSKonstantin Belousov if ((args->owner != 0 && args->count == 0) ||
83603ca6dbdSKonstantin Belousov (args->owner == 0 && args->count != 0))
83703ca6dbdSKonstantin Belousov return (EINVAL);
83803ca6dbdSKonstantin Belousov
83903ca6dbdSKonstantin Belousov mutex = malloc(sizeof(*mutex), M_NTSYNC, M_WAITOK | M_ZERO);
84003ca6dbdSKonstantin Belousov mutex->obj.type = NTSYNC_OBJ_MUTEX;
84103ca6dbdSKonstantin Belousov mutex->obj.is_signaled = ntsync_mutex_is_signaled;
84203ca6dbdSKonstantin Belousov mutex->obj.consume = ntsync_mutex_consume;
84303ca6dbdSKonstantin Belousov mutex->obj.prepare = ntsync_mutex_prepare;
84403ca6dbdSKonstantin Belousov mutex->obj.commit = ntsync_mutex_commit;
84503ca6dbdSKonstantin Belousov mutex->obj.post_commit = ntsync_mutex_post_commit;
84603ca6dbdSKonstantin Belousov mutex->a = *args;
84703ca6dbdSKonstantin Belousov mutex->abandoned = false;
84803ca6dbdSKonstantin Belousov
84903ca6dbdSKonstantin Belousov error = ntsync_create_obj(&mutex->obj, &ntsync_mutex_fops, priv, td);
85003ca6dbdSKonstantin Belousov if (error != 0)
85103ca6dbdSKonstantin Belousov free(mutex, M_NTSYNC);
85203ca6dbdSKonstantin Belousov
85303ca6dbdSKonstantin Belousov return (error);
85403ca6dbdSKonstantin Belousov }
85503ca6dbdSKonstantin Belousov
85603ca6dbdSKonstantin Belousov static bool
ntsync_event_is_signaled(struct ntsync_obj * obj,struct ntsync_wait_state * state,int index)85703ca6dbdSKonstantin Belousov ntsync_event_is_signaled(struct ntsync_obj *obj,
85803ca6dbdSKonstantin Belousov struct ntsync_wait_state *state, int index)
85903ca6dbdSKonstantin Belousov {
86003ca6dbdSKonstantin Belousov struct ntsync_obj_event *event;
86103ca6dbdSKonstantin Belousov
86203ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_EVENT);
86303ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner);
86403ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj);
86503ca6dbdSKonstantin Belousov return (event->a.signaled != 0);
86603ca6dbdSKonstantin Belousov }
86703ca6dbdSKonstantin Belousov
86803ca6dbdSKonstantin Belousov static void
ntsync_event_consume(struct ntsync_obj * obj,struct ntsync_wait_state * state,int index)86903ca6dbdSKonstantin Belousov ntsync_event_consume(struct ntsync_obj *obj, struct ntsync_wait_state *state,
87003ca6dbdSKonstantin Belousov int index)
87103ca6dbdSKonstantin Belousov {
87203ca6dbdSKonstantin Belousov struct ntsync_obj_event *event;
87303ca6dbdSKonstantin Belousov
87403ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_EVENT);
87503ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner);
87603ca6dbdSKonstantin Belousov MPASS(ntsync_event_is_signaled(obj, state, index));
87703ca6dbdSKonstantin Belousov
87803ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj);
87903ca6dbdSKonstantin Belousov if (event->a.manual == 0)
88003ca6dbdSKonstantin Belousov event->a.signaled = 0;
88103ca6dbdSKonstantin Belousov }
88203ca6dbdSKonstantin Belousov
88303ca6dbdSKonstantin Belousov static bool
ntsync_event_prepare(struct ntsync_obj * obj,struct ntsync_wait_state * state,int index,bool * stop)88403ca6dbdSKonstantin Belousov ntsync_event_prepare(struct ntsync_obj *obj, struct ntsync_wait_state *state,
88503ca6dbdSKonstantin Belousov int index, bool *stop)
88603ca6dbdSKonstantin Belousov {
88703ca6dbdSKonstantin Belousov struct ntsync_obj_event *event;
88803ca6dbdSKonstantin Belousov
88903ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_EVENT);
89003ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner);
89103ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj);
89203ca6dbdSKonstantin Belousov if (!ntsync_event_is_signaled(obj, state, index))
89303ca6dbdSKonstantin Belousov return (false);
89403ca6dbdSKonstantin Belousov event->a1 = event->a;
89503ca6dbdSKonstantin Belousov return (true);
89603ca6dbdSKonstantin Belousov }
89703ca6dbdSKonstantin Belousov
89803ca6dbdSKonstantin Belousov static void
ntsync_event_commit(struct ntsync_obj * obj,struct ntsync_wait_state * state,int index)89903ca6dbdSKonstantin Belousov ntsync_event_commit(struct ntsync_obj *obj, struct ntsync_wait_state *state,
90003ca6dbdSKonstantin Belousov int index)
90103ca6dbdSKonstantin Belousov {
90203ca6dbdSKonstantin Belousov struct ntsync_obj_event *event;
90303ca6dbdSKonstantin Belousov
90403ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_EVENT);
90503ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner);
90603ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj);
90703ca6dbdSKonstantin Belousov event->a = event->a1;
90803ca6dbdSKonstantin Belousov if (event->pulse && event->a.manual == 0) {
90903ca6dbdSKonstantin Belousov event->a.signaled = 0;
91003ca6dbdSKonstantin Belousov event->pulse = false;
91103ca6dbdSKonstantin Belousov }
91203ca6dbdSKonstantin Belousov }
91303ca6dbdSKonstantin Belousov
91403ca6dbdSKonstantin Belousov static void
ntsync_event_post_commit(struct ntsync_obj * obj,struct ntsync_wait_state * state,int index)91503ca6dbdSKonstantin Belousov ntsync_event_post_commit(struct ntsync_obj *obj,
91603ca6dbdSKonstantin Belousov struct ntsync_wait_state *state, int index)
91703ca6dbdSKonstantin Belousov {
91803ca6dbdSKonstantin Belousov struct ntsync_obj_event *event;
91903ca6dbdSKonstantin Belousov
92003ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_EVENT);
92103ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner);
92203ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj);
92303ca6dbdSKonstantin Belousov if (event->a.manual == 0)
92403ca6dbdSKonstantin Belousov event->a.signaled = 0;
92503ca6dbdSKonstantin Belousov }
92603ca6dbdSKonstantin Belousov
92703ca6dbdSKonstantin Belousov static int
ntsync_event_close(struct file * fp,struct thread * td)92803ca6dbdSKonstantin Belousov ntsync_event_close(struct file *fp, struct thread *td)
92903ca6dbdSKonstantin Belousov {
93003ca6dbdSKonstantin Belousov struct ntsync_obj_event *event;
93103ca6dbdSKonstantin Belousov
93203ca6dbdSKonstantin Belousov event = fp->f_data;
93303ca6dbdSKonstantin Belousov ntsync_close_obj(&event->obj, td);
93403ca6dbdSKonstantin Belousov free(event, M_NTSYNC);
93503ca6dbdSKonstantin Belousov return (0);
93603ca6dbdSKonstantin Belousov }
93703ca6dbdSKonstantin Belousov
93803ca6dbdSKonstantin Belousov int
ntsync_event_set(struct thread * td,struct file * fp,uint32_t * val)93903ca6dbdSKonstantin Belousov ntsync_event_set(struct thread *td, struct file *fp, uint32_t *val)
94003ca6dbdSKonstantin Belousov {
94103ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
94203ca6dbdSKonstantin Belousov struct ntsync_obj_event *event;
94303ca6dbdSKonstantin Belousov struct ntsync_priv *priv;
94403ca6dbdSKonstantin Belousov uint32_t prev;
94503ca6dbdSKonstantin Belousov
94603ca6dbdSKonstantin Belousov obj = fp->f_data;
94703ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_EVENT)
94803ca6dbdSKonstantin Belousov return (EINVAL);
94903ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj);
95003ca6dbdSKonstantin Belousov priv = obj->owner;
95103ca6dbdSKonstantin Belousov
95203ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv);
95303ca6dbdSKonstantin Belousov prev = event->a.signaled;
95403ca6dbdSKonstantin Belousov event->a.signaled = 1;
95503ca6dbdSKonstantin Belousov ntsync_wakeup_waiters(obj);
95603ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv);
95703ca6dbdSKonstantin Belousov
95803ca6dbdSKonstantin Belousov *val = prev;
95903ca6dbdSKonstantin Belousov return (0);
96003ca6dbdSKonstantin Belousov }
96103ca6dbdSKonstantin Belousov
96203ca6dbdSKonstantin Belousov int
ntsync_event_reset(struct thread * td,struct file * fp,uint32_t * val)96303ca6dbdSKonstantin Belousov ntsync_event_reset(struct thread *td, struct file *fp, uint32_t *val)
96403ca6dbdSKonstantin Belousov {
96503ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
96603ca6dbdSKonstantin Belousov struct ntsync_obj_event *event;
96703ca6dbdSKonstantin Belousov struct ntsync_priv *priv;
96803ca6dbdSKonstantin Belousov uint32_t prev;
96903ca6dbdSKonstantin Belousov
97003ca6dbdSKonstantin Belousov obj = fp->f_data;
97103ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_EVENT)
97203ca6dbdSKonstantin Belousov return (EINVAL);
97303ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj);
97403ca6dbdSKonstantin Belousov priv = obj->owner;
97503ca6dbdSKonstantin Belousov
97603ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv);
97703ca6dbdSKonstantin Belousov prev = event->a.signaled;
97803ca6dbdSKonstantin Belousov event->a.signaled = 0;
97903ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv);
98003ca6dbdSKonstantin Belousov
98103ca6dbdSKonstantin Belousov *val = prev;
98203ca6dbdSKonstantin Belousov return (0);
98303ca6dbdSKonstantin Belousov }
98403ca6dbdSKonstantin Belousov
98503ca6dbdSKonstantin Belousov int
ntsync_event_pulse(struct thread * td,struct file * fp,uint32_t * val)98603ca6dbdSKonstantin Belousov ntsync_event_pulse(struct thread *td, struct file *fp, uint32_t *val)
98703ca6dbdSKonstantin Belousov {
98803ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
98903ca6dbdSKonstantin Belousov struct ntsync_obj_event *event;
99003ca6dbdSKonstantin Belousov struct ntsync_priv *priv;
99103ca6dbdSKonstantin Belousov uint32_t prev;
99203ca6dbdSKonstantin Belousov
99303ca6dbdSKonstantin Belousov obj = fp->f_data;
99403ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_EVENT)
99503ca6dbdSKonstantin Belousov return (EINVAL);
99603ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj);
99703ca6dbdSKonstantin Belousov priv = obj->owner;
99803ca6dbdSKonstantin Belousov
99903ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv);
100003ca6dbdSKonstantin Belousov prev = event->a.signaled;
100103ca6dbdSKonstantin Belousov event->a.signaled = 1;
100203ca6dbdSKonstantin Belousov event->pulse = true;
100303ca6dbdSKonstantin Belousov ntsync_wakeup_waiters(obj);
100403ca6dbdSKonstantin Belousov event->a.signaled = 0;
100503ca6dbdSKonstantin Belousov event->pulse = false;
100603ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv);
100703ca6dbdSKonstantin Belousov
100803ca6dbdSKonstantin Belousov *val = prev;
100903ca6dbdSKonstantin Belousov return (0);
101003ca6dbdSKonstantin Belousov }
101103ca6dbdSKonstantin Belousov
101203ca6dbdSKonstantin Belousov int
ntsync_event_read(struct thread * td,struct file * fp,struct ntsync_event_args * a)101303ca6dbdSKonstantin Belousov ntsync_event_read(struct thread *td, struct file *fp,
101403ca6dbdSKonstantin Belousov struct ntsync_event_args *a)
101503ca6dbdSKonstantin Belousov {
101603ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
101703ca6dbdSKonstantin Belousov struct ntsync_obj_event *event;
101803ca6dbdSKonstantin Belousov struct ntsync_priv *priv;
101903ca6dbdSKonstantin Belousov
102003ca6dbdSKonstantin Belousov obj = fp->f_data;
102103ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_EVENT)
102203ca6dbdSKonstantin Belousov return (EINVAL);
102303ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj);
102403ca6dbdSKonstantin Belousov priv = obj->owner;
102503ca6dbdSKonstantin Belousov
102603ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv);
102703ca6dbdSKonstantin Belousov *a = event->a;
102803ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv);
102903ca6dbdSKonstantin Belousov
103003ca6dbdSKonstantin Belousov return (0);
103103ca6dbdSKonstantin Belousov }
103203ca6dbdSKonstantin Belousov
103303ca6dbdSKonstantin Belousov static int
ntsync_event_ioctl(struct file * fp,u_long com,void * data,struct ucred * active_cred,struct thread * td)103403ca6dbdSKonstantin Belousov ntsync_event_ioctl(struct file *fp, u_long com, void *data,
103503ca6dbdSKonstantin Belousov struct ucred *active_cred, struct thread *td)
103603ca6dbdSKonstantin Belousov {
103703ca6dbdSKonstantin Belousov int error;
103803ca6dbdSKonstantin Belousov
103903ca6dbdSKonstantin Belousov switch (com) {
104003ca6dbdSKonstantin Belousov case NTSYNC_IOC_EVENT_SET:
104103ca6dbdSKonstantin Belousov error = ntsync_event_set(td, fp, data);
104203ca6dbdSKonstantin Belousov break;
104303ca6dbdSKonstantin Belousov case NTSYNC_IOC_EVENT_RESET:
104403ca6dbdSKonstantin Belousov error = ntsync_event_reset(td, fp, data);
104503ca6dbdSKonstantin Belousov break;
104603ca6dbdSKonstantin Belousov case NTSYNC_IOC_EVENT_PULSE:
104703ca6dbdSKonstantin Belousov error = ntsync_event_pulse(td, fp, data);
104803ca6dbdSKonstantin Belousov break;
104903ca6dbdSKonstantin Belousov case NTSYNC_IOC_EVENT_READ:
105003ca6dbdSKonstantin Belousov error = ntsync_event_read(td, fp, data);
105103ca6dbdSKonstantin Belousov break;
105203ca6dbdSKonstantin Belousov default:
105303ca6dbdSKonstantin Belousov error = ENOTTY;
105403ca6dbdSKonstantin Belousov break;
105503ca6dbdSKonstantin Belousov }
105603ca6dbdSKonstantin Belousov return (error);
105703ca6dbdSKonstantin Belousov }
105803ca6dbdSKonstantin Belousov
105903ca6dbdSKonstantin Belousov static int
ntsync_event_stat(struct file * fp,struct stat * sbp,struct ucred * cred)106003ca6dbdSKonstantin Belousov ntsync_event_stat(struct file *fp, struct stat *sbp, struct ucred *cred)
106103ca6dbdSKonstantin Belousov {
106203ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
106303ca6dbdSKonstantin Belousov struct ntsync_obj_event *event;
106403ca6dbdSKonstantin Belousov
106503ca6dbdSKonstantin Belousov MPASS(fp->f_type == DTYPE_NTSYNC);
106603ca6dbdSKonstantin Belousov obj = fp->f_data;
106703ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_EVENT);
106803ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj);
106903ca6dbdSKonstantin Belousov
107003ca6dbdSKonstantin Belousov memset(sbp, 0, sizeof(*sbp));
107103ca6dbdSKonstantin Belousov sbp->st_mode = S_IFREG /* XXXKIB */ | S_IRUSR | S_IWUSR;
107203ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(obj->owner);
107303ca6dbdSKonstantin Belousov sbp->st_size = event->a.signaled;
107403ca6dbdSKonstantin Belousov sbp->st_nlink = event->a.manual;
107503ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(obj->owner);
107603ca6dbdSKonstantin Belousov return (0);
107703ca6dbdSKonstantin Belousov }
107803ca6dbdSKonstantin Belousov
107903ca6dbdSKonstantin Belousov static int
ntsync_event_fill_kinfo(struct file * fp,struct kinfo_file * kif,struct filedesc * fdp)108003ca6dbdSKonstantin Belousov ntsync_event_fill_kinfo(struct file *fp, struct kinfo_file *kif,
108103ca6dbdSKonstantin Belousov struct filedesc *fdp)
108203ca6dbdSKonstantin Belousov {
1083*d0ea3affSKonstantin Belousov struct ntsync_obj *obj;
1084*d0ea3affSKonstantin Belousov struct ntsync_obj_event *event;
1085*d0ea3affSKonstantin Belousov
1086*d0ea3affSKonstantin Belousov MPASS(fp->f_type == DTYPE_NTSYNC);
1087*d0ea3affSKonstantin Belousov obj = fp->f_data;
1088*d0ea3affSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_EVENT);
1089*d0ea3affSKonstantin Belousov event = OBJ_TO_EVENT(obj);
1090*d0ea3affSKonstantin Belousov
1091*d0ea3affSKonstantin Belousov kif->kf_type = KF_TYPE_NTSYNC;
1092*d0ea3affSKonstantin Belousov kif->kf_un.kf_ntsync.kf_ntsync_type = KF_NTSYNC_TYPE_EVENT;
1093*d0ea3affSKonstantin Belousov kif->kf_un.kf_ntsync.kf_ntsync_dev = (uintptr_t)obj->owner;
1094*d0ea3affSKonstantin Belousov kif->kf_un.kf_ntsync.kf_ntsync_un.kf_ntsync_event.signaled =
1095*d0ea3affSKonstantin Belousov event->a.signaled;
1096*d0ea3affSKonstantin Belousov kif->kf_un.kf_ntsync.kf_ntsync_un.kf_ntsync_event.manual =
1097*d0ea3affSKonstantin Belousov event->a.manual;
109803ca6dbdSKonstantin Belousov return (0);
109903ca6dbdSKonstantin Belousov }
110003ca6dbdSKonstantin Belousov
110103ca6dbdSKonstantin Belousov struct fileops ntsync_event_fops = {
110203ca6dbdSKonstantin Belousov .fo_read = invfo_rdwr,
110303ca6dbdSKonstantin Belousov .fo_write = invfo_rdwr,
110403ca6dbdSKonstantin Belousov .fo_truncate = invfo_truncate,
110503ca6dbdSKonstantin Belousov .fo_ioctl = ntsync_event_ioctl,
110603ca6dbdSKonstantin Belousov .fo_poll = invfo_poll,
110703ca6dbdSKonstantin Belousov .fo_kqfilter = invfo_kqfilter,
110803ca6dbdSKonstantin Belousov .fo_stat = ntsync_event_stat,
110903ca6dbdSKonstantin Belousov .fo_close = ntsync_event_close,
111003ca6dbdSKonstantin Belousov .fo_chmod = invfo_chmod,
111103ca6dbdSKonstantin Belousov .fo_chown = invfo_chown,
111203ca6dbdSKonstantin Belousov .fo_sendfile = invfo_sendfile,
111303ca6dbdSKonstantin Belousov .fo_fill_kinfo = ntsync_event_fill_kinfo,
111403ca6dbdSKonstantin Belousov .fo_flags = DFLAG_PASSABLE,
111503ca6dbdSKonstantin Belousov };
111603ca6dbdSKonstantin Belousov
111703ca6dbdSKonstantin Belousov static int
ntsync_create_event(struct ntsync_event_args * args,struct ntsync_priv * priv,struct thread * td)111803ca6dbdSKonstantin Belousov ntsync_create_event(struct ntsync_event_args *args, struct ntsync_priv *priv,
111903ca6dbdSKonstantin Belousov struct thread *td)
112003ca6dbdSKonstantin Belousov {
112103ca6dbdSKonstantin Belousov struct ntsync_obj_event *event;
112203ca6dbdSKonstantin Belousov int error;
112303ca6dbdSKonstantin Belousov
112403ca6dbdSKonstantin Belousov event = malloc(sizeof(*event), M_NTSYNC, M_WAITOK | M_ZERO);
112503ca6dbdSKonstantin Belousov event->obj.type = NTSYNC_OBJ_EVENT;
112603ca6dbdSKonstantin Belousov event->obj.is_signaled = ntsync_event_is_signaled;
112703ca6dbdSKonstantin Belousov event->obj.consume = ntsync_event_consume;
112803ca6dbdSKonstantin Belousov event->obj.prepare = ntsync_event_prepare;
112903ca6dbdSKonstantin Belousov event->obj.commit = ntsync_event_commit;
113003ca6dbdSKonstantin Belousov event->obj.post_commit = ntsync_event_post_commit;
113103ca6dbdSKonstantin Belousov event->a = *args;
113203ca6dbdSKonstantin Belousov
113303ca6dbdSKonstantin Belousov error = ntsync_create_obj(&event->obj, &ntsync_event_fops, priv, td);
113403ca6dbdSKonstantin Belousov if (error != 0)
113503ca6dbdSKonstantin Belousov free(event, M_NTSYNC);
113603ca6dbdSKonstantin Belousov
113703ca6dbdSKonstantin Belousov return (error);
113803ca6dbdSKonstantin Belousov }
113903ca6dbdSKonstantin Belousov
114003ca6dbdSKonstantin Belousov static void
ntsync_free_priv(struct ntsync_priv * priv)114103ca6dbdSKonstantin Belousov ntsync_free_priv(struct ntsync_priv *priv)
114203ca6dbdSKonstantin Belousov {
114303ca6dbdSKonstantin Belousov bool do_free;
114403ca6dbdSKonstantin Belousov
114503ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv);
114603ca6dbdSKonstantin Belousov do_free = priv->closed && priv->objs_cnt == 0;
114703ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv);
114803ca6dbdSKonstantin Belousov if (do_free) {
114903ca6dbdSKonstantin Belousov mtx_destroy(&priv->lock);
115003ca6dbdSKonstantin Belousov free(priv, M_NTSYNC);
115103ca6dbdSKonstantin Belousov }
115203ca6dbdSKonstantin Belousov }
115303ca6dbdSKonstantin Belousov
115403ca6dbdSKonstantin Belousov static void
ntsync_priv_dtr(void * data)115503ca6dbdSKonstantin Belousov ntsync_priv_dtr(void *data)
115603ca6dbdSKonstantin Belousov {
115703ca6dbdSKonstantin Belousov ntsync_free_priv(data);
115803ca6dbdSKonstantin Belousov }
115903ca6dbdSKonstantin Belousov
116003ca6dbdSKonstantin Belousov static int
ntsync_open(struct cdev * dev,int oflags,int devtype,struct thread * td)116103ca6dbdSKonstantin Belousov ntsync_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
116203ca6dbdSKonstantin Belousov {
116303ca6dbdSKonstantin Belousov struct ntsync_priv *priv;
116403ca6dbdSKonstantin Belousov
116503ca6dbdSKonstantin Belousov priv = malloc(sizeof(*priv), M_NTSYNC, M_WAITOK);
116603ca6dbdSKonstantin Belousov priv->closed = false;
116703ca6dbdSKonstantin Belousov priv->objs_cnt = 0;
116803ca6dbdSKonstantin Belousov mtx_init(&priv->lock, "ntsync", "ntsync", MTX_DEF | MTX_NEW);
116903ca6dbdSKonstantin Belousov devfs_set_cdevpriv(priv, ntsync_priv_dtr);
117003ca6dbdSKonstantin Belousov return (0);
117103ca6dbdSKonstantin Belousov }
117203ca6dbdSKonstantin Belousov
117303ca6dbdSKonstantin Belousov static int
ntsync_close(struct cdev * dev,int fflag,int devtype,struct thread * td)117403ca6dbdSKonstantin Belousov ntsync_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
117503ca6dbdSKonstantin Belousov {
117603ca6dbdSKonstantin Belousov struct ntsync_priv *priv;
117703ca6dbdSKonstantin Belousov void *a;
117803ca6dbdSKonstantin Belousov int error;
117903ca6dbdSKonstantin Belousov
118003ca6dbdSKonstantin Belousov error = devfs_get_cdevpriv(&a);
118103ca6dbdSKonstantin Belousov if (error == 0) {
118203ca6dbdSKonstantin Belousov priv = a;
118303ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv);
118403ca6dbdSKonstantin Belousov priv->closed = true;
118503ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv);
118603ca6dbdSKonstantin Belousov }
118703ca6dbdSKonstantin Belousov devfs_clear_cdevpriv();
118803ca6dbdSKonstantin Belousov return (0);
118903ca6dbdSKonstantin Belousov }
119003ca6dbdSKonstantin Belousov
119103ca6dbdSKonstantin Belousov static int
ntsync_wait_state_get(struct ntsync_wait_args * nwa,u_long cmd,struct ntsync_priv * owner,struct ntsync_wait_state ** statep,struct thread * td)119203ca6dbdSKonstantin Belousov ntsync_wait_state_get(struct ntsync_wait_args *nwa, u_long cmd,
119303ca6dbdSKonstantin Belousov struct ntsync_priv *owner, struct ntsync_wait_state **statep,
119403ca6dbdSKonstantin Belousov struct thread *td)
119503ca6dbdSKonstantin Belousov {
119603ca6dbdSKonstantin Belousov struct ntsync_wait_state *state;
119703ca6dbdSKonstantin Belousov struct ntsync_obj *obj;
119803ca6dbdSKonstantin Belousov struct bintime btb;
119903ca6dbdSKonstantin Belousov int error, i, j;
120003ca6dbdSKonstantin Belousov
120103ca6dbdSKonstantin Belousov if (nwa->count > NTSYNC_MAX_WAIT_COUNT)
120203ca6dbdSKonstantin Belousov return (EINVAL);
120303ca6dbdSKonstantin Belousov if ((nwa->flags & ~NTSYNC_WAIT_REALTIME) != 0)
120403ca6dbdSKonstantin Belousov return (EINVAL);
120503ca6dbdSKonstantin Belousov
120603ca6dbdSKonstantin Belousov state = malloc(sizeof(*state), M_NTSYNC, M_WAITOK | M_ZERO);
120703ca6dbdSKonstantin Belousov state->nwa = nwa;
120803ca6dbdSKonstantin Belousov state->owner = owner;
120903ca6dbdSKonstantin Belousov state->all = cmd == NTSYNC_IOC_WAIT_ALL;
121003ca6dbdSKonstantin Belousov state->any = !state->all;
121103ca6dbdSKonstantin Belousov error = copyin((void *)(uintptr_t)nwa->objs, &state->fds[0],
121203ca6dbdSKonstantin Belousov nwa->count * sizeof(state->fds[0]));
121303ca6dbdSKonstantin Belousov if (error != 0)
121403ca6dbdSKonstantin Belousov return (error);
121503ca6dbdSKonstantin Belousov
121603ca6dbdSKonstantin Belousov i = 0;
121703ca6dbdSKonstantin Belousov if (nwa->alert != 0) {
121803ca6dbdSKonstantin Belousov error = fget_cap(td, nwa->alert, &cap_no_rights, NULL,
121903ca6dbdSKonstantin Belousov &state->fp_alert, NULL);
122003ca6dbdSKonstantin Belousov if (error != 0) {
122103ca6dbdSKonstantin Belousov state->fp_alert = NULL;
122203ca6dbdSKonstantin Belousov goto error_out;
122303ca6dbdSKonstantin Belousov }
122403ca6dbdSKonstantin Belousov if (state->fp_alert->f_type != DTYPE_NTSYNC) {
122503ca6dbdSKonstantin Belousov error = EINVAL;
122603ca6dbdSKonstantin Belousov goto error_out;
122703ca6dbdSKonstantin Belousov }
122803ca6dbdSKonstantin Belousov obj = state->fp_alert->f_data;
122903ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_EVENT || obj->owner != owner) {
123003ca6dbdSKonstantin Belousov error = EINVAL;
123103ca6dbdSKonstantin Belousov goto error_out;
123203ca6dbdSKonstantin Belousov }
123303ca6dbdSKonstantin Belousov state->alert_event = OBJ_TO_EVENT(obj);
123403ca6dbdSKonstantin Belousov }
123503ca6dbdSKonstantin Belousov
123603ca6dbdSKonstantin Belousov for (; i < nwa->count; i++) {
123703ca6dbdSKonstantin Belousov error = fget_cap(td, state->fds[i], &cap_no_rights, NULL,
123803ca6dbdSKonstantin Belousov &state->fps[i], NULL);
123903ca6dbdSKonstantin Belousov if (error != 0) {
124003ca6dbdSKonstantin Belousov state->fps[i] = NULL;
124103ca6dbdSKonstantin Belousov goto error_out;
124203ca6dbdSKonstantin Belousov }
124303ca6dbdSKonstantin Belousov if (state->fps[i]->f_type != DTYPE_NTSYNC ||
124403ca6dbdSKonstantin Belousov (obj = state->fps[i]->f_data)->owner != owner) {
124503ca6dbdSKonstantin Belousov i++;
124603ca6dbdSKonstantin Belousov error = EINVAL;
124703ca6dbdSKonstantin Belousov goto error_out;
124803ca6dbdSKonstantin Belousov }
124903ca6dbdSKonstantin Belousov }
125003ca6dbdSKonstantin Belousov
125103ca6dbdSKonstantin Belousov state->obj_count = nwa->count;
125203ca6dbdSKonstantin Belousov for (i = 0; i < nwa->count; i++)
125303ca6dbdSKonstantin Belousov state->objs[i] = state->fps[i]->f_data;
125403ca6dbdSKonstantin Belousov if (state->alert_event != NULL) {
125503ca6dbdSKonstantin Belousov state->objs[i] = &state->alert_event->obj;
125603ca6dbdSKonstantin Belousov state->obj_count++;
125703ca6dbdSKonstantin Belousov }
125803ca6dbdSKonstantin Belousov
125903ca6dbdSKonstantin Belousov if (state->all) {
126003ca6dbdSKonstantin Belousov /* Check no dups */
126103ca6dbdSKonstantin Belousov for (i = 0; i < state->obj_count; i++) {
126203ca6dbdSKonstantin Belousov obj = state->objs[i];
126303ca6dbdSKonstantin Belousov for (j = i + 1; j < state->obj_count; j++) {
126403ca6dbdSKonstantin Belousov if (obj == state->objs[j]) {
126503ca6dbdSKonstantin Belousov i = state->obj_count;
126603ca6dbdSKonstantin Belousov error = EINVAL;
126703ca6dbdSKonstantin Belousov goto error_out;
126803ca6dbdSKonstantin Belousov }
126903ca6dbdSKonstantin Belousov }
127003ca6dbdSKonstantin Belousov }
127103ca6dbdSKonstantin Belousov }
127203ca6dbdSKonstantin Belousov
127303ca6dbdSKonstantin Belousov if (nwa->timeout == UINT64_MAX) {
127403ca6dbdSKonstantin Belousov state->sb = 0;
127503ca6dbdSKonstantin Belousov } else {
127603ca6dbdSKonstantin Belousov state->sb = nstosbt(nwa->timeout);
127703ca6dbdSKonstantin Belousov if ((nwa->flags & NTSYNC_WAIT_REALTIME) != 0) {
127803ca6dbdSKonstantin Belousov getboottimebin(&btb);
127903ca6dbdSKonstantin Belousov state->sb += bttosbt(btb);
128003ca6dbdSKonstantin Belousov }
128103ca6dbdSKonstantin Belousov }
128203ca6dbdSKonstantin Belousov
128303ca6dbdSKonstantin Belousov *statep = state;
128403ca6dbdSKonstantin Belousov return (0);
128503ca6dbdSKonstantin Belousov
128603ca6dbdSKonstantin Belousov error_out:
128703ca6dbdSKonstantin Belousov for (j = 0; j < i; j++)
128803ca6dbdSKonstantin Belousov fdrop(state->fps[j], td);
128903ca6dbdSKonstantin Belousov if (state->fp_alert != NULL)
129003ca6dbdSKonstantin Belousov fdrop(state->fp_alert, td);
129103ca6dbdSKonstantin Belousov return (error);
129203ca6dbdSKonstantin Belousov }
129303ca6dbdSKonstantin Belousov
129403ca6dbdSKonstantin Belousov static void
ntsync_wait_state_put(struct ntsync_wait_state * state,struct thread * td)129503ca6dbdSKonstantin Belousov ntsync_wait_state_put(struct ntsync_wait_state *state, struct thread *td)
129603ca6dbdSKonstantin Belousov {
129703ca6dbdSKonstantin Belousov int i;
129803ca6dbdSKonstantin Belousov
129903ca6dbdSKonstantin Belousov for (i = 0; i < state->nwa->count; i++)
130003ca6dbdSKonstantin Belousov fdrop(state->fps[i], td);
130103ca6dbdSKonstantin Belousov if (state->fp_alert != NULL)
130203ca6dbdSKonstantin Belousov fdrop(state->fp_alert, td);
130303ca6dbdSKonstantin Belousov free(state, M_NTSYNC);
130403ca6dbdSKonstantin Belousov }
130503ca6dbdSKonstantin Belousov
130603ca6dbdSKonstantin Belousov static int
ntsync_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int fflag,struct thread * td)130703ca6dbdSKonstantin Belousov ntsync_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
130803ca6dbdSKonstantin Belousov struct thread *td)
130903ca6dbdSKonstantin Belousov {
131003ca6dbdSKonstantin Belousov struct ntsync_priv *owner;
131103ca6dbdSKonstantin Belousov struct ntsync_wait_args *nwa;
131203ca6dbdSKonstantin Belousov struct ntsync_wait_state *state;
131303ca6dbdSKonstantin Belousov void *a;
131403ca6dbdSKonstantin Belousov int error;
131503ca6dbdSKonstantin Belousov
131603ca6dbdSKonstantin Belousov error = devfs_get_cdevpriv(&a);
131703ca6dbdSKonstantin Belousov if (error != 0)
131803ca6dbdSKonstantin Belousov return (error);
131903ca6dbdSKonstantin Belousov owner = a;
132003ca6dbdSKonstantin Belousov
132103ca6dbdSKonstantin Belousov switch (cmd) {
132203ca6dbdSKonstantin Belousov case NTSYNC_IOC_CREATE_SEM:
132303ca6dbdSKonstantin Belousov error = ntsync_create_sem((struct ntsync_sem_args *)data,
132403ca6dbdSKonstantin Belousov owner, td);
132503ca6dbdSKonstantin Belousov break;
132603ca6dbdSKonstantin Belousov case NTSYNC_IOC_CREATE_MUTEX:
132703ca6dbdSKonstantin Belousov error = ntsync_create_mutex((struct ntsync_mutex_args *)data,
132803ca6dbdSKonstantin Belousov owner, td);
132903ca6dbdSKonstantin Belousov break;
133003ca6dbdSKonstantin Belousov case NTSYNC_IOC_CREATE_EVENT:
133103ca6dbdSKonstantin Belousov error = ntsync_create_event((struct ntsync_event_args *)data,
133203ca6dbdSKonstantin Belousov owner, td);
133303ca6dbdSKonstantin Belousov break;
133403ca6dbdSKonstantin Belousov case NTSYNC_IOC_WAIT_ANY:
133503ca6dbdSKonstantin Belousov nwa = (struct ntsync_wait_args *)data;
133603ca6dbdSKonstantin Belousov error = ntsync_wait_state_get(nwa, cmd, owner, &state, td);
133703ca6dbdSKonstantin Belousov if (error != 0)
133803ca6dbdSKonstantin Belousov break;
133903ca6dbdSKonstantin Belousov error = ntsync_wait(state, td);
134003ca6dbdSKonstantin Belousov if (error == 0) {
134103ca6dbdSKonstantin Belousov nwa->index = state->index;
134203ca6dbdSKonstantin Belousov error = ntsync_ioctl_copyout(td, nwa, sizeof(*nwa));
134303ca6dbdSKonstantin Belousov if (error == 0)
134403ca6dbdSKonstantin Belousov error = state->error;
134503ca6dbdSKonstantin Belousov }
134603ca6dbdSKonstantin Belousov ntsync_wait_state_put(state, td);
134703ca6dbdSKonstantin Belousov break;
134803ca6dbdSKonstantin Belousov case NTSYNC_IOC_WAIT_ALL:
134903ca6dbdSKonstantin Belousov nwa = (struct ntsync_wait_args *)data;
135003ca6dbdSKonstantin Belousov error = ntsync_wait_state_get(nwa, cmd, owner, &state, td);
135103ca6dbdSKonstantin Belousov if (error != 0)
135203ca6dbdSKonstantin Belousov break;
135303ca6dbdSKonstantin Belousov error = ntsync_wait(state, td);
135403ca6dbdSKonstantin Belousov if (error == 0) {
135503ca6dbdSKonstantin Belousov nwa->index = state->index;
135603ca6dbdSKonstantin Belousov error = ntsync_ioctl_copyout(td, nwa, sizeof(*nwa));
135703ca6dbdSKonstantin Belousov if (error == 0)
135803ca6dbdSKonstantin Belousov error = state->error;
135903ca6dbdSKonstantin Belousov }
136003ca6dbdSKonstantin Belousov ntsync_wait_state_put(state, td);
136103ca6dbdSKonstantin Belousov break;
136203ca6dbdSKonstantin Belousov
136303ca6dbdSKonstantin Belousov default:
136403ca6dbdSKonstantin Belousov error = ENOTTY;
136503ca6dbdSKonstantin Belousov break;
136603ca6dbdSKonstantin Belousov }
136703ca6dbdSKonstantin Belousov return (error);
136803ca6dbdSKonstantin Belousov }
136903ca6dbdSKonstantin Belousov
137003ca6dbdSKonstantin Belousov struct cdevsw ntsync_cdevsw = {
137103ca6dbdSKonstantin Belousov .d_version = D_VERSION,
137203ca6dbdSKonstantin Belousov .d_flags = 0,
137303ca6dbdSKonstantin Belousov .d_open = ntsync_open,
137403ca6dbdSKonstantin Belousov .d_close = ntsync_close,
137503ca6dbdSKonstantin Belousov .d_ioctl = ntsync_ioctl,
137603ca6dbdSKonstantin Belousov .d_name = "ntsync",
137703ca6dbdSKonstantin Belousov };
137803ca6dbdSKonstantin Belousov
137903ca6dbdSKonstantin Belousov static int
ntsync_modevent(module_t mod __unused,int type,void * data __unused)138003ca6dbdSKonstantin Belousov ntsync_modevent(module_t mod __unused, int type, void *data __unused)
138103ca6dbdSKonstantin Belousov {
138203ca6dbdSKonstantin Belousov struct make_dev_args mda;
138303ca6dbdSKonstantin Belousov int error;
138403ca6dbdSKonstantin Belousov
138503ca6dbdSKonstantin Belousov error = 0;
138603ca6dbdSKonstantin Belousov switch (type) {
138703ca6dbdSKonstantin Belousov case MOD_LOAD:
138803ca6dbdSKonstantin Belousov make_dev_args_init(&mda);
138903ca6dbdSKonstantin Belousov mda.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME;
139003ca6dbdSKonstantin Belousov mda.mda_devsw = &ntsync_cdevsw;
139103ca6dbdSKonstantin Belousov mda.mda_uid = UID_ROOT;
139203ca6dbdSKonstantin Belousov mda.mda_gid = GID_GAMES;
139303ca6dbdSKonstantin Belousov mda.mda_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
139403ca6dbdSKonstantin Belousov S_IROTH | S_IWOTH;
139503ca6dbdSKonstantin Belousov
139603ca6dbdSKonstantin Belousov error = make_dev_s(&mda, &ntsync_cdev, "ntsync");
139703ca6dbdSKonstantin Belousov if (error != 0) {
139803ca6dbdSKonstantin Belousov printf("cannot create ntsync dev err %d\n", error);
139903ca6dbdSKonstantin Belousov break;
140003ca6dbdSKonstantin Belousov }
140103ca6dbdSKonstantin Belousov if (bootverbose)
140203ca6dbdSKonstantin Belousov printf("ntsync\n");
140303ca6dbdSKonstantin Belousov break;
140403ca6dbdSKonstantin Belousov
140503ca6dbdSKonstantin Belousov case MOD_UNLOAD:
140603ca6dbdSKonstantin Belousov destroy_dev(ntsync_cdev);
140703ca6dbdSKonstantin Belousov break;
140803ca6dbdSKonstantin Belousov
140903ca6dbdSKonstantin Belousov case MOD_SHUTDOWN:
141003ca6dbdSKonstantin Belousov break;
141103ca6dbdSKonstantin Belousov
141203ca6dbdSKonstantin Belousov default:
141303ca6dbdSKonstantin Belousov error = EOPNOTSUPP;
141403ca6dbdSKonstantin Belousov }
141503ca6dbdSKonstantin Belousov
141603ca6dbdSKonstantin Belousov return (error);
141703ca6dbdSKonstantin Belousov }
141803ca6dbdSKonstantin Belousov
141903ca6dbdSKonstantin Belousov DEV_MODULE(ntsync, ntsync_modevent, NULL);
142003ca6dbdSKonstantin Belousov MODULE_VERSION(ntsync, 1);
1421