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);
}
}