- if (kn == NULL) {
- if (kev->flags & EV_ADD) {
- struct fileproc *knote_fp = NULL;
-
- /* grab a file reference for the new knote */
- if (fops->f_isfd) {
- if ((error = fp_lookup(p, kev->ident, &knote_fp, 0)) != 0) {
- goto out;
- }
- }
-
- kn = knote_alloc();
- if (kn == NULL) {
- error = ENOMEM;
- if (knote_fp != NULL)
- fp_drop(p, kev->ident, knote_fp, 0);
- goto out;
- }
-
- kn->kn_fp = knote_fp;
- knote_set_kq(kn, kq);
- kqueue_retain(kq); /* retain a kq ref */
- kn->kn_filtid = ~kev->filter;
- kn->kn_inuse = 1; /* for f_attach() */
- kn->kn_status = KN_ATTACHING | KN_ATTACHED;
-
- /* was vanish support requested */
- if (kev->flags & EV_VANISHED) {
- kev->flags &= ~EV_VANISHED;
- kn->kn_status |= KN_REQVANISH;
- }
-
- /* snapshot matching/dispatching protcol flags into knote */
- if (kev->flags & EV_DISPATCH)
- kn->kn_status |= KN_DISPATCH;
- if (kev->flags & EV_UDATA_SPECIFIC)
- kn->kn_status |= KN_UDATA_SPECIFIC;
-
- /*
- * copy the kevent state into knote
- * protocol is that fflags and data
- * are saved off, and cleared before
- * calling the attach routine.
- */
- kn->kn_kevent = *kev;
- kn->kn_sfflags = kev->fflags;
- kn->kn_sdata = kev->data;
- kn->kn_fflags = 0;
- kn->kn_data = 0;
-
- /* invoke pthread kext to convert kevent qos to thread qos */
- knote_canonicalize_kevent_qos(kn);
- knote_set_qos_index(kn, qos_index_from_qos(kn, kn->kn_qos, FALSE));
-
- /* before anyone can find it */
- if (kev->flags & EV_DISABLE) {
- /*
- * do this before anyone can find it,
- * this can't call knote_disable() because it expects having
- * the kqlock held
- */
- kn->kn_status |= KN_DISABLED;
- }
-
- /* Add the knote for lookup thru the fd table */
- error = kq_add_knote(kq, kn, kev, p, &knoteuse_flags);
- if (error) {
- (void)kqueue_release(kq, KQUEUE_CANT_BE_LAST_REF);
- knote_free(kn);
- if (knote_fp != NULL)
- fp_drop(p, kev->ident, knote_fp, 0);
-
- if (error == ERESTART) {
- error = 0;
- goto restart;
- }
- goto out;
- }
-
- /* fp reference count now applies to knote */
- /* rwlock boost is now held */
-
- /* call filter attach routine */
- result = fops->f_attach(kn, kev);
-
- /*
- * Trade knote use count for kq lock.
- * Cannot be dropped because we held
- * KN_ATTACHING throughout.
- */
- knoteuse2kqlock(kq, kn, KNUSE_STEAL_DROP | knoteuse_flags);
-
- if (kn->kn_flags & EV_ERROR) {
- /*
- * Failed to attach correctly, so drop.
- * All other possible users/droppers
- * have deferred to us. Save the error
- * to return to our caller.
- */
- kn->kn_status &= ~KN_ATTACHED;
- kn->kn_status |= KN_DROPPING;
- error = kn->kn_data;
- kqunlock(kq);
- knote_drop(kn, p);
- goto out;
- }
-
- /* end "attaching" phase - now just attached */
- kn->kn_status &= ~KN_ATTACHING;
-
- if (kn->kn_status & KN_DROPPING) {
- /*
- * Attach succeeded, but someone else
- * deferred their drop - now we have
- * to do it for them.
- */
- kqunlock(kq);
- knote_drop(kn, p);
- goto out;
- }
-
- /* Mark the thread request overcommit - if appropos */
- knote_set_qos_overcommit(kn);
-
- /*
- * If the attach routine indicated that an
- * event is already fired, activate the knote.
- */
- if (result)
- knote_activate(kn);
-
- if (knote_fops(kn)->f_post_attach) {
- error = knote_fops(kn)->f_post_attach(kn, kev);
- if (error) {
- kqunlock(kq);
- goto out;
- }
- }
-
- } else {
- if ((kev_flags & (EV_ADD | EV_DELETE)) == (EV_ADD | EV_DELETE) &&
- (kq->kq_state & KQ_WORKLOOP)) {
- /*
- * For workloops, understand EV_ADD|EV_DELETE as a "soft" delete
- * that doesn't care about ENOENT, so just pretend the deletion
- * happened.
- */
- } else {
- error = ENOENT;
- }
- goto out;
- }
-
- } else {
- /* existing knote: kqueue lock already taken by kq_find_knote_and_kq_lock */
-
- if ((kn->kn_status & (KN_DROPPING | KN_ATTACHING)) != 0) {
- /*
- * The knote is not in a stable state, wait for that
- * transition to complete and then redrive the lookup.
- */
- knoteusewait(kq, kn);
- goto restart;
- }
-
- if (kev->flags & EV_DELETE) {
-
- /*
- * If attempting to delete a disabled dispatch2 knote,
- * we must wait for the knote to be re-enabled (unless
- * it is being re-enabled atomically here).
- */
- if ((kev->flags & EV_ENABLE) == 0 &&
- (kn->kn_status & (KN_DISPATCH2 | KN_DISABLED)) ==
- (KN_DISPATCH2 | KN_DISABLED)) {
- kn->kn_status |= KN_DEFERDELETE;
- kqunlock(kq);
- error = EINPROGRESS;
- } else if (knote_fops(kn)->f_drop_and_unlock) {
- /*
- * The filter has requested to handle EV_DELETE events
- *
- * ERESTART means the kevent has to be re-evaluated
- */
- error = knote_fops(kn)->f_drop_and_unlock(kn, kev);
- if (error == ERESTART) {
- error = 0;
- goto restart;
- }
- } else if (kqlock2knotedrop(kq, kn)) {
- /* standard/default EV_DELETE path */
- knote_drop(kn, p);
- } else {
- /*
- * The kqueue is unlocked, it's not being
- * dropped, and kqlock2knotedrop returned 0:
- * this means that someone stole the drop of
- * the knote from us.
- */
- error = EINPROGRESS;
- }
- goto out;
- }
-
- /*
- * If we are re-enabling a deferred-delete knote,
- * just enable it now and avoid calling the
- * filter touch routine (it has delivered its
- * last event already).
- */
- if ((kev->flags & EV_ENABLE) &&
- (kn->kn_status & KN_DEFERDELETE)) {
- assert(kn->kn_status & KN_DISABLED);
- knote_activate(kn);
- knote_enable(kn);
- kqunlock(kq);
- goto out;
- }
-
- /*
- * If we are disabling, do it before unlocking and
- * calling the touch routine (so no processing can
- * see the new kevent state before the disable is
- * applied).
- */
- if (kev->flags & EV_DISABLE)
- knote_disable(kn);
-
- /*
- * Convert the kqlock to a use reference on the
- * knote so we can call the filter touch routine.
- */
- if (knoteuse_needs_boost(kn, kev)) {
- knoteuse_flags |= KNUSE_BOOST;
- }
- if (kqlock2knoteuse(kq, kn, knoteuse_flags)) {
- /*
- * Call touch routine to notify filter of changes
- * in filter values (and to re-determine if any
- * events are fired).
- */
- result = knote_fops(kn)->f_touch(kn, kev);
-
- /* Get the kq lock back (don't defer droppers). */
- if (!knoteuse2kqlock(kq, kn, knoteuse_flags)) {
- kqunlock(kq);
- goto out;
- }
-
- /* Handle errors during touch routine */
- if (kev->flags & EV_ERROR) {
- error = kev->data;
- kqunlock(kq);
- goto out;
- }
-
- /* Activate it if the touch routine said to */
- if (result)
- knote_activate(kn);
- }
-
- /* Enable the knote if called for */
- if (kev->flags & EV_ENABLE)
- knote_enable(kn);
-
- }
-
- /* still have kqlock held and knote is valid */
- kqunlock(kq);
-
-out:
- /* output local errors through the kevent */
- if (error) {
- kev->flags |= EV_ERROR;
- kev->data = error;
- }
-}