我有一个 kqueue 正在监视一个项目:一个空的 Mach 端口集。kevent64
表示没有可用的事件,并select
表示 kqueue 尚未准备好读取。但是poll
说 kqueue是可读的!kevent64
- 尽管在随后调用以读取假定准备好的事件时,情况似乎并非如此。
我正在使用的代码如下。你可以用类似的东西来构建它gcc -Wall -std=c99 -o test test.c
,然后用它./test
或其他东西运行它。它打印出以下返回值kevent64
:(在尝试读取 1 而无需等待后实际检索到的事件计数)、select
(轮询后准备读取的文件描述符计数)和poll
(轮询后准备读取的文件描述符计数)。
我期望的输出是这样的,表明kevent64
,select
并且poll
所有人都同意 kqueue 是空的。
$ ./kqueue_poll_machport
kevent64: 0
select: 0
poll: 0 (revents: 0)
kevent64: 0
但我实际上得到的是这个,显示kevent64
并select
说一件事,poll
另一件事 - 而且,即使在poll
表明 kqueue 是可读的之后,kevent64
仍然说没有要读取的事件(这是第二次kevent64
调用的原因)。
$ ./kqueue_poll_machport
kevent64: 0
select: 0
poll: 1 (revents: 1)
kevent64: 0
revents
( is的 1 值POLLIN
,据说,表示可以在没有阻塞的情况下读取数据。如果我单独指定POLLRDNORM
,结果是相同的POLLRDBAND
。)
为什么会出现差异?
我的测试代码:
#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);
}
}