1

I've got a kqueue watching a single item: an empty Mach port set. kevent64 says there are no events available, and select indicates the kqueue is not ready for reading. But poll says the kqueue is readable! - though this doesn't appear to be the case when subsequently calling kevent64 to read the supposedly ready event(s).

The code I'm using is below. You can build it with something like gcc -Wall -std=c99 -o test test.c, and then run it with ./test or whatever. It prints out return values from kevent64 (count of events actually retrieved after an attempt was made to read 1 without waiting), select (count of file descriptors ready for reading after polling), and poll (count of file descriptors ready for reading after polling).

The output I'd expect would be something like this, indicating that kevent64, select and poll all agree that the kqueue is empty.

$ ./kqueue_poll_machport
kevent64: 0
select: 0
poll: 0 (revents: 0)
kevent64: 0

But what I actually get is this, showing that kevent64 and select say one thing, and poll another - and, furthermore, that even after poll has indicated the kqueue is readable, kevent64 still says there is no event to be read (this being the reason for the second kevent64 call).

$ ./kqueue_poll_machport
kevent64: 0
select: 0
poll: 1 (revents: 1)
kevent64: 0

(The 1 value for revents is POLLIN, indicating, supposedly, that data may be read without blocking. The result is the same if I specify POLLRDNORM and POLLRDBAND independently.)

Why the discrepancy?

My test code:

#include <stdio.h>
#include <assert.h>
#include <mach/mach.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <sys/select.h>
#include <poll.h>

int main(void) {
    kern_return_t kr;
    int rc;

    int kq=kqueue();
    assert(kq!=-1);

    mach_port_name_t port_set;
    kr=mach_port_allocate(mach_task_self(),MACH_PORT_RIGHT_PORT_SET,&port_set);
    assert(kr==KERN_SUCCESS);

    {
        const struct kevent64_s events[]={
            {
                .flags=EV_ADD|EV_ENABLE,
                .filter=EVFILT_MACHPORT,
                .ident=port_set,
            },
        };

        rc=kevent64(kq,events,sizeof events/sizeof events[0],NULL,0,0,NULL);
        assert(rc==0);
    }

    /* Events available? */
    {
        const struct timespec NO_TIMEOUT={0,0};
        struct kevent64_s event;
        rc=kevent64(kq,NULL,0,&event,1,0,&NO_TIMEOUT);
        printf("kevent64: %d\n",rc);
    }

    /* Test readability with select. */
    {
        const struct timeval NO_TIMEOUT={0,0};
        fd_set rd;
        FD_ZERO(&rd);
        FD_SET(kq,&rd);
        rc=select(kq+1,&rd,NULL,NULL,&NO_TIMEOUT);
        printf("select: %d\n",rc);
    }

    /* Test readibility with poll. */
    {
        struct pollfd fds[]={
            {
                .fd=kq,
                .events=POLLIN,
            },
        };
        rc=poll(fds,sizeof fds/sizeof fds[0],0);
        printf("poll: %d (revents: %d)\n",rc,fds[0].revents);
    }

    /* Events available? */
    {
        const struct timespec NO_TIMEOUT={0,0};
        struct kevent64_s event;
        rc=kevent64(kq,NULL,0,&event,1,0,&NO_TIMEOUT);
        printf("kevent64: %d\n",rc);
    }
}
Tom Seddon
  • 2,648
  • 1
  • 19
  • 28

0 Answers0