参考:
man.openbsd.org/kqueue.2#kq… people.freebsd.org/~jlemon/pap…
kqueue() provides a generic method of notifying the user when an event happens or a condition holds, based on the results of small pieces of kernel code termed “filters”. A kevent is identified by the (ident, filter) pair; there may only be one unique kevent per kqueue.
The filter is executed upon the initial registration of a kevent in order to detect whether a preexisting condition is present, and is also executed whenever an event is passed to the filter for evaluation. If the filter determines that the condition should be reported, then the kevent is placed on the kqueue for the user to retrieve.
The filter is also run when the user attempts to retrieve the kevent from the kqueue. If the filter indicates that the condition that triggered the event no longer holds, the kevent is removed from the kqueue and is not returned.
Multiple events which trigger the filter do not result in multiple kevents being placed on the kqueue; instead, the filter will aggregate the events into a single struct kevent. Calling close(2) on a file descriptor will remove any kevents that reference the descriptor.
api
kqueue() creates a new kernel event queue and returns a descriptor. The queue is not inherited by a child created with fork(2). Similarly, kqueues cannot be passed across UNIX-domain sockets.
kevent() is used to register events with the queue, and return any pending events to the user. changelist is a pointer to an array of kevent structures, as defined in <sys/event.h>. All changes contained in the changelist are applied before any pending events are read from the queue. nchanges gives the size of changelist. eventlist is a pointer to an array of kevent structures. nevents determines the size of eventlist. When nevents is zero, kevent() will return immediately even if there is a timeout specified, unlike select(2). If timeout is not NULL, it specifies a maximum interval to wait for an event, which will be interpreted as a struct timespec. If timeout is NULL, kevent() waits indefinitely. To effect a poll, the timeout argument should not be NULL, pointing to a zero-valued struct timespec. The same array may be used for the changelist and eventlist.
EV_SET() is a macro which is provided for ease of initializing a kevent structure.
implementation
Figure 9: Two kqueues, their descriptor arrays, and active lists. Note that kq A has two knotes queued in its active list, while kq B has none. The socket has a klist for each sockbuf, and as shown, knotes on a klist may belong to different kqueues.