+/* Kqueue EVFILT_MACHPORT support */
+
+#include <sys/errno.h>
+
+static int filt_machportattach(struct knote *kn);
+static void filt_machportdetach(struct knote *kn);
+static int filt_machport(struct knote *kn, long hint);
+static void filt_machporttouch(struct knote *kn, struct kevent64_s *kev, long type);
+static unsigned filt_machportpeek(struct knote *kn);
+struct filterops machport_filtops = {
+ .f_attach = filt_machportattach,
+ .f_detach = filt_machportdetach,
+ .f_event = filt_machport,
+ .f_touch = filt_machporttouch,
+ .f_peek = filt_machportpeek,
+};
+
+static int
+filt_machportattach(
+ struct knote *kn)
+{
+ mach_port_name_t name = (mach_port_name_t)kn->kn_kevent.ident;
+ wait_queue_link_t wql = wait_queue_link_allocate();
+ ipc_pset_t pset = IPS_NULL;
+ int result = ENOSYS;
+ kern_return_t kr;
+
+ kr = ipc_object_translate(current_space(), name,
+ MACH_PORT_RIGHT_PORT_SET,
+ (ipc_object_t *)&pset);
+ if (kr != KERN_SUCCESS) {
+ wait_queue_link_free(wql);
+ return (kr == KERN_INVALID_NAME ? ENOENT : ENOTSUP);
+ }
+ /* We've got a lock on pset */
+
+ /*
+ * Bind the portset wait queue directly to knote/kqueue.
+ * This allows us to just use wait_queue foo to effect a wakeup,
+ * rather than having to call knote() from the Mach code on each
+ * message.
+ */
+ result = knote_link_wait_queue(kn, &pset->ips_messages.imq_wait_queue, wql);
+ if (result == 0) {
+ /* keep a reference for the knote */
+ kn->kn_ptr.p_pset = pset;
+ ips_reference(pset);
+ ips_unlock(pset);
+ return 0;
+ }
+
+ ips_unlock(pset);
+ wait_queue_link_free(wql);
+ return result;
+}