+ 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);
+ }
+
+ /*
+ * 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_kevent.udata = kev->udata;
+ if (fops->f_isfd || fops->f_touch == NULL) {
+ kn->kn_sfflags = kev->fflags;
+ kn->kn_sdata = kev->data;
+ }
+
+ /*
+ * 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. Attaches
+ * running in parallel may also drop/modify the
+ * knote. Wait for those to complete as well and
+ * then start over if we encounter one.
+ */
+ if (!kqlock2knoteusewait(kq, kn)) {
+ /* kqueue, proc_fdlock both unlocked */
+ goto restart;
+ }
+
+ /*
+ * Call touch routine to notify filter of changes
+ * in filter values.
+ */
+ if (!fops->f_isfd && fops->f_touch != NULL)
+ fops->f_touch(kn, kev, EVENT_REGISTER);
+ }
+ /* still have use ref on knote */
+
+ /*
+ * If the knote is not marked to always stay enqueued,
+ * invoke the filter routine to see if it should be
+ * enqueued now.
+ */
+ if ((kn->kn_status & KN_STAYQUEUED) == 0 && kn->kn_fop->f_event(kn, 0)) {
+ if (knoteuse2kqlock(kq, kn))
+ knote_activate(kn, 1);
+ kqunlock(kq);
+ } else {
+ knote_put(kn);
+ }
+
+done:
+ if (fp != NULL)
+ fp_drop(p, kev->ident, fp, 0);
+ return (error);
+}
+
+
+/*
+ * knote_process - process a triggered event
+ *
+ * Validate that it is really still a triggered event
+ * by calling the filter routines (if necessary). Hold
+ * a use reference on the knote to avoid it being detached.
+ * If it is still considered triggered, invoke the callback
+ * routine provided and move it to the provided inprocess
+ * queue.
+ *
+ * caller holds a reference on the kqueue.
+ * kqueue locked on entry and exit - but may be dropped
+ */
+static int
+knote_process(struct knote *kn,
+ kevent_callback_t callback,
+ void *data,
+ struct kqtailq *inprocessp,
+ struct proc *p)
+{
+ struct kqueue *kq = kn->kn_kq;
+ struct kevent64_s kev;
+ int touch;
+ int result;
+ int error;
+
+ /*
+ * Determine the kevent state we want to return.
+ *
+ * Some event states need to be revalidated before returning
+ * them, others we take the snapshot at the time the event
+ * was enqueued.
+ *
+ * Events with non-NULL f_touch operations must be touched.
+ * Triggered events must fill in kev for the callback.
+ *
+ * Convert our lock to a use-count and call the event's
+ * filter routine(s) to update.
+ */
+ if ((kn->kn_status & KN_DISABLED) != 0) {
+ result = 0;
+ touch = 0;
+ } else {
+ int revalidate;
+
+ result = 1;
+ revalidate = ((kn->kn_status & KN_STAYQUEUED) != 0 ||
+ (kn->kn_flags & EV_ONESHOT) == 0);
+ touch = (!kn->kn_fop->f_isfd && kn->kn_fop->f_touch != NULL);
+
+ if (revalidate || touch) {
+ if (revalidate)
+ knote_deactivate(kn);
+
+ /* call the filter/touch routines with just a ref */
+ if (kqlock2knoteuse(kq, kn)) {
+
+ /* if we have to revalidate, call the filter */
+ if (revalidate) {
+ result = kn->kn_fop->f_event(kn, 0);
+ }
+
+ /* capture the kevent data - using touch if specified */
+ if (result && touch) {
+ kn->kn_fop->f_touch(kn, &kev, EVENT_PROCESS);
+ }
+
+ /* convert back to a kqlock - bail if the knote went away */
+ if (!knoteuse2kqlock(kq, kn)) {
+ return EJUSTRETURN;
+ } else if (result) {
+ /* if revalidated as alive, make sure it's active */
+ if (!(kn->kn_status & KN_ACTIVE)) {
+ knote_activate(kn, 0);
+ }
+
+ /* capture all events that occurred during filter */
+ if (!touch) {
+ kev = kn->kn_kevent;
+ }
+
+ } else if ((kn->kn_status & KN_STAYQUEUED) == 0) {
+ /* was already dequeued, so just bail on this one */
+ return EJUSTRETURN;
+ }
+ } else {
+ return EJUSTRETURN;
+ }
+ } else {
+ kev = kn->kn_kevent;