Solved Question with Understanding the `kevent` structure

I'm teaching my self how to work with kqueue/kevent in order to port some software over to FreeBSD. I've already read through the (very limited) tutorials on the subject, and the FreeBSD documentation on the subject kqueue().

I think I got most of it, but there is one item I am currently having trouble understanding. That's is how some examples use the "kevent" structure as an array and others do not.

For example, the manual pages show a non-array example:

Code:
struct kevent event;
EV_SET(&event, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE, 0, NULL);

Then there is another that does it slightly differently (https://dev.to/frevib/a-tcp-server-with-kqueue-527):

Code:
struct kevent change_event[4]
EV_SET(change_event, socket_listen_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);

Next I come across something like NetBSD's example which is suggesting that the array is how you monitor multiple file descriptors (https://wiki.netbsd.org/tutorials/kqueue_tutorial/):
Code:
kevent ev[N];
int i;

for (i = 0; i < N; i++)
   EV_SET(&ev[i], sckfd[i], EVFILT_READ, EV_ADD, 0, 0, 0);


Further examples from that NetBSD tutorial show how to monitor for different types of events (https://repo.or.cz/eleutheria.git/blob/master:/kqueue/kqclient.c):

Code:
struct kevent chlist[2];
EV_SET(&chlist[0], sckfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
EV_SET(&chlist[1], fileno(stdin), EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);

Finally, there is this odd one from Stack Overflow which is I guess is just an alternative to the array notation (https://stackoverflow.com/questions/15843147/use-kqueue-to-respond-to-more-than-one-event-type):

Code:
struct kevent *ke = malloc(sizeof(struct kevent) * 2);
EV_SET(ke, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_DELETE | NOTE_RENAME, 0, NULL);
EV_SET(ke + 1, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);

How does this work?
 
Last edited:
Related (yet different question). Can the filter 'EV_EOF' be a direct replacement for 'EPOLLHUP' and 'EPOLLRDHUP' epoll counterparts when monitoring socket file descriptors?
 
See the code in Compiler Explorer

(I only copied the C99 version of the EV_SET macro).

The macro uses an unnamed temporary. It uses named initialization to initialize that temporary and then assigns the temporary to the dereferenced struct kevent pointer. Even without optimization the compiler doesn't bother creating the temporary and directly copies the values into the fields of the structure.

The array versions do the same thing except that they do it per-element of the array. For instance "&ev" takes the address of the i-th element of the array. With one exception.

Code:
struct kevent change_event[4]
EV_SET(change_event, socket_listen_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);

This one only initializes the first of the four elements in the array.
 
Back
Top