Search code examples
macosselectfreebsdkqueue

Is it possible to poll a kqueue's file descriptor with `select()`?


When you create a kqueue with kqueue() you get back a file descriptor. But it appears that this file descriptor cannot be meaningfully polled with select(). I understand that the standard way to poll/read from a kqueue() is with kevent(...) but I'm trying to integrate with some legacy code that polls file descriptors using select().

The goal here was to be able to fire a "user event" that can be detected by this select-based polling mechanism (even if the event eventually needs to be "consumed" using kevent() later). This looked like the kind of thing EVFILT_USER was born to do, but a quick experiment indicates that select() doesn't report the kqueue's fd as being ready to read when an event is added (and triggered) in the kqueue, it just times out (or blocks forever). (But an equivalent kevent() call does see/return the event.)

Am I doing something wrong? Or is it just not possible to poll a kqueue's fd with select()?


Solution

  • The paper, describing kqueue/kevent says (sect 6.5):

    Since an ordinary file descriptor references the kqueue, it can take part in any operations that normally can per - formed on a descriptor. The application may select(), poll(), close(), or even create a kevent referencing a kqueue;

    This is indeed the case for FreeBSD, i've checked this with following code:

      struct kevent e;
      fd_set fdset;
      int kq=kqueue();
    
      EV_SET(&e, 1, EVFILT_USER, EV_ADD, 0, 0, NULL);
      kevent(kq, &e, 1, 0, 0, 0); // register USER event filter
    
      EV_SET(&e, 1, EVFILT_USER, EV_ADD, NOTE_TRIGGER, 0, NULL);
      kevent(kq, &e, 1, 0, 0, 0); // trigger USER event
    
      FD_ZERO(&fdset);
      FD_SET(kq,&fdset);
    
      select(FD_SETSIZE,&fdset, 0, 0, 0); // wait for activity on kq
    
      int res = kevent(kq, 0, 0, &e, 1, 0); // get the event