+static inline struct kqueue *knote_get_kq(struct knote *kn)
+{
+ if (!(kn->kn_kq_packed))
+ return 0;
+ else
+ return (struct kqueue *)((uintptr_t)(kn->kn_kq_packed) + (uintptr_t)VM_MIN_KERNEL_AND_KEXT_ADDRESS);
+}
+
+static inline void knote_set_kq(struct knote *kn, void *kq)
+{
+ if (!kq)
+ kn->kn_kq_packed = 0;
+ else {
+ uint64_t offset = ((uintptr_t)kq - (uintptr_t)VM_MIN_KERNEL_AND_KEXT_ADDRESS);
+ kn->kn_kq_packed = offset;
+ }
+}
+
+static inline int knote_get_seltype(struct knote *kn)
+{
+ switch (kn->kn_filter) {
+ case EVFILT_READ:
+ return FREAD;
+ case EVFILT_WRITE:
+ return FWRITE;
+ default:
+ panic("%s(%p): invalid filter %d\n",
+ __func__, kn, kn->kn_filter);
+ return 0;
+ }
+}
+
+static inline void knote_set_error(struct knote *kn, int error)
+{
+ kn->kn_flags |= EV_ERROR;
+ kn->kn_data = error;
+}
+
+struct filt_process_s {
+ int fp_fd;
+ unsigned int fp_flags;
+ user_addr_t fp_data_out;
+ user_size_t fp_data_size;
+ user_size_t fp_data_resid;
+};
+typedef struct filt_process_s *filt_process_data_t;
+
+/*
+ * Filter operators
+ *
+ * These routines, provided by each filter, are called to attach, detach, deliver events,
+ * change/update filter registration and process/deliver events. They are called with the
+ * with a use-count referenced knote, with the kq unlocked. Here are more details:
+ *
+ * f_isfd -
+ * identifies if the "ident" field in the kevent structure is a file-descriptor.
+ *
+ * If so, the knote is associated with the file descriptor prior to attach and
+ * auto-removed when the file descriptor is closed (this latter behavior may change
+ * for EV_DISPATCH2 kevent types to allow delivery of events identifying unintended
+ * closes).
+ *
+ * Otherwise the knote is hashed by the ident and has no auto-close behavior.
+ *
+ * f_adjusts_qos -
+ * identifies if the filter can adjust its QoS during its lifetime.
+ *
+ * Currently, EVFILT_MAACHPORT is the only filter using this facility.
+ *
+ * f_needs_boost -
+ * [OPTIONAL] used by filters to communicate they need to hold a boost
+ * while holding a usecount on this knote. This is called with the kqlock
+ * held.
+ *
+ * This is only used by EVFILT_WORKLOOP currently.
+ *
+ * f_attach -
+ * called to attach the knote to the underlying object that will be delivering events
+ * through it when EV_ADD is supplied and no existing matching event is found
+ *
+ * provided a knote that is pre-attached to the fd or hashed (see above) but is
+ * specially marked to avoid concurrent access until the attach is complete. The
+ * kevent structure embedded in this knote has been filled in with a sanitized
+ * version of the user-supplied kevent data. However, the user-supplied filter-specific
+ * flags (fflags) and data fields have been moved into the knote's kn_sfflags and kn_sdata
+ * fields respectively. These are usually interpretted as a set of "interest" flags and
+ * data by each filter - to be matched against delivered events.
+ *
+ * The attach operator indicated errors by setting the EV_ERROR flog in the flags field
+ * embedded in the knote's kevent structure - with the specific error indicated in the
+ * corresponding data field.
+ *
+ * The return value indicates if the knote should already be considered "activated" at
+ * the time of attach (one or more of the interest events has already occured).
+ *
+ * f_post_attach -
+ * [OPTIONAL] called after a successful attach, with the kqueue lock held,
+ * returns lock held, may drop and re-acquire
+ *
+ * If this function is non-null, then it indicates that the filter wants
+ * to perform an action after a successful ATTACH of a knote.
+ *
+ * Currently, EVFILT_WORKLOOP is the only filter using this facility.
+ *
+ * The return value indicates an error to report to userland.
+ *
+ *
+ * f_detach -
+ * called to disassociate the knote from the underlying object delivering events
+ * the filter should not attempt to deliver events through this knote after this
+ * operation returns control to the kq system.
+ *
+ * f_event -
+ * if the knote() function (or KNOTE() macro) is called against a list of knotes,
+ * this operator will be called on each knote in the list.
+ *
+ * The "hint" parameter is completely filter-specific, but usually indicates an
+ * event or set of events that have occured against the source object associated
+ * with the list.
+ *
+ * The return value indicates if the knote should already be considered "activated" at
+ * the time of attach (one or more of the interest events has already occured).
+ *
+ * f_drop_and_unlock -
+ * [OPTIONAL] called with the kqueue locked, and has to unlock
+ *
+ * If this function is non-null, then it indicates that the filter
+ * wants to handle EV_DELETE events. This is necessary if a particular
+ * filter needs to synchronize knote deletion with its own filter lock.
+ * Currently, EVFILT_WORKLOOP is the only filter using this facility.
+ *
+ * The return value indicates an error during the knote drop, i.e., the
+ * knote still exists and user space should re-drive the EV_DELETE.
+ *
+ * If the return value is ERESTART, kevent_register() is called from
+ * scratch again (useful to wait for usecounts to drop and then
+ * reevaluate the relevance of that drop)
+ *
+ *
+ * f_process -
+ * called when attempting to deliver triggered events to user-space.
+ *
+ * If the knote was previously activated, this operator will be called when a
+ * thread is trying to deliver events to user-space. The filter gets one last
+ * chance to determine if the event/events are still interesting for this knote
+ * (are the conditions still right to deliver an event). If so, the filter
+ * fills in the output kevent structure with the information to be delivered.
+ *
+ * The input context/data parameter is used during event delivery. Some
+ * filters allow additional data delivery as part of event delivery. This
+ * context field indicates if space was made available for these additional
+ * items and how that space is to be allocated/carved-out.
+ *
+ * The filter may set EV_CLEAR or EV_ONESHOT in the output flags field to indicate
+ * special post-delivery dispositions for the knote.
+ *
+ * EV_CLEAR - indicates that all matching events have been delivered. Even
+ * though there were events to deliver now, there will not be any
+ * more until some additional events are delivered to the knote
+ * via the f_event operator, or the interest set is changed via
+ * the f_touch operator. The knote can remain deactivated after
+ * processing this event delivery.
+ *
+ * EV_ONESHOT - indicates that this is the last event to be delivered via
+ * this knote. It will automatically be deleted upon delivery
+ * (or if in dispatch-mode, upon re-enablement after this delivery).
+ *
+ * The return value indicates if the knote has delivered an output event.
+ * Unless one of the special output flags was set in the output kevent, a non-
+ * zero return value ALSO indicates that the knote should be re-activated
+ * for future event processing (in case it delivers level-based or a multi-edge
+ * type events like message queues that already exist).
+ *
+ * NOTE: In the future, the boolean may change to an enum that allows more
+ * explicit indication of just delivering a current event vs delivering
+ * an event with more events still pending.
+ *
+ * f_touch -
+ * called to update the knote with new state from the user during EVFILT_ADD/ENABLE/DISABLE
+ * on an already-attached knote.
+ *
+ * f_touch should copy relevant new data from the kevent into the knote.
+ * (if KN_UDATA_SPECIFIC is not set, you may need to update the udata too)
+ *
+ * operator must lock against concurrent f_event and f_process operations.
+ *
+ * A return value of 1 indicates that the knote should now be considered 'activated'.
+ *
+ * f_touch can set EV_ERROR with specific error in the data field to return an error to the client.
+ * You should return 1 to indicate that the kevent needs to be activated and processed.
+ *
+ * f_peek -
+ * For knotes marked KN_STAYACTIVE, indicate if the knote is truly active at
+ * the moment (not used for event delivery, but for status checks).
+ */
+