+ /*
+ * kn now contains the matching knote, or NULL if no match
+ */
+ if (kn == NULL) {
+ if ((kev->flags & (EV_ADD|EV_DELETE)) == EV_ADD) {
+ kn = knote_alloc();
+ if (kn == NULL) {
+ proc_fdunlock(p);
+ error = ENOMEM;
+ goto done;
+ }
+ kn->kn_fp = fp;
+ kn->kn_kq = kq;
+ kn->kn_tq = &kq->kq_head;
+ kn->kn_fop = fops;
+ kn->kn_sfflags = kev->fflags;
+ kn->kn_sdata = kev->data;
+ kev->fflags = 0;
+ kev->data = 0;
+ kn->kn_kevent = *kev;
+ kn->kn_inuse = 1; /* for f_attach() */
+ kn->kn_status = 0;
+
+ /* before anyone can find it */
+ if (kev->flags & EV_DISABLE)
+ kn->kn_status |= KN_DISABLED;
+
+ error = knote_fdpattach(kn, fdp, p);
+ proc_fdunlock(p);
+
+ if (error) {
+ knote_free(kn);
+ goto done;
+ }
+
+ /*
+ * apply reference count to knote structure, and
+ * do not release it at the end of this routine.
+ */
+ fp = NULL;
+
+ /*
+ * If the attach fails here, we can drop it knowing
+ * that nobody else has a reference to the knote.
+ */
+ if ((error = fops->f_attach(kn)) != 0) {
+ knote_drop(kn, p);
+ goto done;
+ }
+ } else {
+ proc_fdunlock(p);
+ error = ENOENT;
+ goto done;
+ }
+ } else {
+ /* existing knote - get kqueue lock */
+ kqlock(kq);
+ proc_fdunlock(p);
+
+ if (kev->flags & EV_DELETE) {
+ knote_dequeue(kn);
+ kn->kn_status |= KN_DISABLED;
+ if (kqlock2knotedrop(kq, kn)) {
+ kn->kn_fop->f_detach(kn);
+ knote_drop(kn, p);
+ }
+ goto done;
+ }
+
+ /* update status flags for existing knote */
+ if (kev->flags & EV_DISABLE) {
+ knote_dequeue(kn);
+ kn->kn_status |= KN_DISABLED;
+ } else if (kev->flags & EV_ENABLE) {
+ kn->kn_status &= ~KN_DISABLED;
+ if (kn->kn_status & KN_ACTIVE)
+ knote_enqueue(kn);
+ }
+
+ /*
+ * If somebody is in the middle of dropping this
+ * knote - go find/insert a new one. But we have
+ * wait for this one to go away first.
+ */
+ if (!kqlock2knoteusewait(kq, kn))
+ /* kqueue unlocked */
+ goto restart;
+
+ /*
+ * The user may change some filter values after the
+ * initial EV_ADD, but doing so will not reset any
+ * filter which have already been triggered.
+ */
+ kn->kn_sfflags = kev->fflags;
+ kn->kn_sdata = kev->data;
+ kn->kn_kevent.udata = kev->udata;
+ }
+
+ /* still have use ref on knote */
+ if (kn->kn_fop->f_event(kn, 0)) {
+ if (knoteuse2kqlock(kq, kn))
+ knote_activate(kn);
+ kqunlock(kq);
+ } else {
+ knote_put(kn);
+ }
+
+done:
+ if (fp != NULL)
+ fp_drop(p, kev->ident, fp, 0);
+ return (error);
+}
+
+/*
+ * kevent_process - process the triggered events in a kqueue
+ *
+ * Walk the queued knotes and validate that they are
+ * really still triggered events by calling the filter
+ * routines (if necessary). Hold a use reference on
+ * the knote to avoid it being detached. For each event
+ * that is still considered triggered, invoke the
+ * callback routine provided.
+ *
+ * caller holds a reference on the kqueue.
+ * kqueue locked on entry and exit - but may be dropped
+ */
+
+static int
+kevent_process(struct kqueue *kq,
+ kevent_callback_t callback,
+ void *data,
+ int *countp,
+ struct proc *p)
+{
+ struct knote *kn;
+ struct kevent kev;
+ int nevents;
+ int error;
+
+ restart:
+ if (kq->kq_count == 0) {
+ *countp = 0;
+ return 0;
+ }
+
+ /* if someone else is processing the queue, wait */
+ if (!TAILQ_EMPTY(&kq->kq_inprocess)) {
+ assert_wait(&kq->kq_inprocess, THREAD_UNINT);
+ kq->kq_state |= KQ_PROCWAIT;
+ kqunlock(kq);
+ thread_block(THREAD_CONTINUE_NULL);
+ kqlock(kq);
+ goto restart;
+ }
+
+ error = 0;
+ nevents = 0;
+ while (error == 0 &&
+ (kn = TAILQ_FIRST(&kq->kq_head)) != NULL) {
+
+ /*
+ * move knote to the processed queue.
+ * this is also protected by the kq lock.
+ */
+ assert(kn->kn_tq == &kq->kq_head);
+ TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe);
+ kn->kn_tq = &kq->kq_inprocess;
+ TAILQ_INSERT_TAIL(&kq->kq_inprocess, kn, kn_tqe);
+
+ /*
+ * Non-EV_ONESHOT events must be re-validated.
+ *
+ * Convert our lock to a use-count and call the event's
+ * filter routine to update.
+ *
+ * If the event is dropping (or no longer valid), we
+ * already have it off the active queue, so just
+ * finish the job of deactivating it.
+ */
+ if ((kn->kn_flags & EV_ONESHOT) == 0) {
+ int result;