前面讲过evport/epoll的实现,下来我们继续看看我们kqueue在redis中的使用
1:首先通过kqueue申请提供给系统监控的fd
typedef struct aeApiState {
int kqfd;
struct kevent *events;
} aeApiState;
static int aeApiCreate(aeEventLoop *eventLoop) {
aeApiState *state = zmalloc(sizeof(aeApiState));
if (!state) return -1;
state->events = zmalloc(sizeof(struct kevent)*eventLoop->setsize);
if (!state->events) {
zfree(state);
return -1;
}
#通过kqueue申请提供给系统监控的fd
state->kqfd = kqueue();
if (state->kqfd == -1) {
zfree(state->events);
zfree(state);
return -1;
}
eventLoop->apidata = state;
return 0;
}
2:通过kevent 添加要监控的事件包括读和写事件
static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
aeApiState *state = eventLoop->apidata;
struct kevent ke;
#根据mask判断是读事件,然后通过kevent 设置到kernel space中
if (mask & AE_READABLE) {
EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
if (kevent(state->kqfd, &ke, 1, NULL, 0, NULL) == -1) return -1;
}
#根据mask判断是写事件,然后通过kevent 设置到kernel space中
if (mask & AE_WRITABLE) {
EV_SET(&ke, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
if (kevent(state->kqfd, &ke, 1, NULL, 0, NULL) == -1) return -1;
}
#注意这里是if的关系,可以同时监控读和写事件
return 0;
}
3:通过kevent 开监控fd
static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
aeApiState *state = eventLoop->apidata;
int retval, numevents = 0;
#根据时间设置kevent的超时时间,分成两种
if (tvp != NULL) {
struct timespec timeout;
timeout.tv_sec = tvp->tv_sec;
timeout.tv_nsec = tvp->tv_usec * 1000;
retval = kevent(state->kqfd, NULL, 0, state->events, eventLoop->setsize,
&timeout);
} else {
retval = kevent(state->kqfd, NULL, 0, state->events, eventLoop->setsize,
NULL);
}
#非timeout则retval 返回值大于零
if (retval > 0) {
int j;
numevents = retval;
#遍历state->events 数组
for(j = 0; j < numevents; j++) {
int mask = 0;
struct kevent *e = state->events+j;
#根据filter 分为读和写事件
if (e->filter == EVFILT_READ) mask |= AE_READABLE;
if (e->filter == EVFILT_WRITE) mask |= AE_WRITABLE;
#保持fd和mask,然后返回给用户
eventLoop->fired[j].fd = e->ident;
eventLoop->fired[j].mask = mask;
}
}
return numevents;
}
redis中io复用之kqueue
最新推荐文章于 2024-09-10 15:55:21 发布