// 监听端口 if (server.port != 0 && listenToPort(server.port,&server.ipfd) == C_ERR) { serverLog(LL_WARNING, "Failed listening on port %u (TCP), aborting.", server.port); exit(1); }
......
// 创建 时间事件,处理后台任务 serverCron,比如客户端超时、淘汰过期数据等 /* Create the timer callback, this is our way to process many background * operations incrementally, like clients timeout, eviction of unaccessed * expired keys and so forth. */ if (aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) { serverPanic("Can't create event loop timers."); exit(1); }
// 创建 文件事件处理函数,用于监听连接 /* Create an event handler for accepting new connections in TCP and Unix * domain sockets. */ if (createSocketAcceptHandler(&server.ipfd, acceptTcpHandler) != C_OK) { serverPanic("Unrecoverable error creating TCP socket accept handler."); } if (createSocketAcceptHandler(&server.tlsfd, acceptTLSHandler) != C_OK) { serverPanic("Unrecoverable error creating TLS socket accept handler."); } if (server.sofd > 0 && aeCreateFileEvent(server.el,server.sofd,AE_READABLE, acceptUnixHandler,NULL) == AE_ERR) serverPanic("Unrecoverable error creating server.sofd file event.");
/* Register a readable event for the pipe used to awake the event loop * when a blocked client in a module needs attention. */ if (aeCreateFileEvent(server.el, server.module_blocked_pipe[0], AE_READABLE, moduleBlockedClientPipeReadable,NULL) == AE_ERR) { serverPanic( "Error registering the readable event for the module " "blocked clients subsystem."); }
aeApiCreate 针对不同的操作系统有不同的实现。比如 Unix 中是 ae_kqueue.c,这里我们看下 Linux 中的 ae_epoll.c,其中就调用了 epoll_create 方法
1 2 3 4 5 6 7 8
staticintaeApiCreate(aeEventLoop *eventLoop){ ...... state->events = zmalloc(sizeof(struct epoll_event)*eventLoop->setsize); ...... state->epfd = epoll_create(1024); /* 1024 is just a hint for the kernel */ ...... return0; }
intaeApiCreate(aeEventLoop *eventLoop); voidaeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask); voidaeApiResize(aeEventLoop *eventLoop, int setsize); voidaeApiFree(aeEventLoop *eventLoop); intaeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask); voidaeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask); intaeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp); char *aeApiName(void);
/* * 一般情况下,先处理所有到期的 时间事件(time event),再处理所有文件事件(file event)(因为时间事件可能会触发新的文件事件) * 如果 flags 中没有特殊的标记位的话,这个方法会 sleep,直到 文件事件 触发,或者下一个 时间事件 到来。 * * If flags is 0, the function does nothing and returns. * if flags has AE_ALL_EVENTS set, all the kind of events are processed. * if flags has AE_FILE_EVENTS set, file events are processed. * if flags has AE_TIME_EVENTS set, time events are processed. * if flags has AE_DONT_WAIT set the function returns ASAP until all * the events that's possible to process without to wait are processed. * if flags has AE_CALL_AFTER_SLEEP set, the aftersleep callback is called. * if flags has AE_CALL_BEFORE_SLEEP set, the beforesleep callback is called. * * 方法返回处理完成的事件的数量 */ intaeProcessEvents(aeEventLoop *eventLoop, int flags) { ......
/* 这里就是 event loop 的核心逻辑 */ /* Note that we want to call select() even if there are no * file events to process as long as we want to process time * events, in order to sleep until the next time event is ready * to fire. */ if (eventLoop->maxfd != -1 || ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) {
/* Before sleep callback. */ if (eventLoop->beforesleep != NULL && flags & AE_CALL_BEFORE_SLEEP) eventLoop->beforesleep(eventLoop);
/* 调用 multiplexing API,这个方法里,调用了 epoll_wait,所以会阻塞住, * epoll_wait 超时时间是 tvp,如果 tvp 是空,则一直阻塞,直到下一个事件到来 * will return only on timeout or when some event fires. */ numevents = aeApiPoll(eventLoop, tvp);
/* After sleep callback. */ if (eventLoop->aftersleep != NULL && flags & AE_CALL_AFTER_SLEEP) eventLoop->aftersleep(eventLoop);
// 遍历事件列表,依次处理事件 for (j = 0; j < numevents; j++) { aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd]; int mask = eventLoop->fired[j].mask; int fd = eventLoop->fired[j].fd; int fired = 0; /* Number of events fired for current fd. */
/* 处理读事件 */ if (!invert && fe->mask & mask & AE_READABLE) { fe->rfileProc(eventLoop,fd,fe->clientData,mask); fired++; fe = &eventLoop->events[fd]; /* Refresh in case of resize. */ }
staticintprocessTimeEvents(aeEventLoop *eventLoop){ int processed = 0; aeTimeEvent *te; longlong maxId;
te = eventLoop->timeEventHead; maxId = eventLoop->timeEventNextId-1; monotime now = getMonotonicUs(); while(te) {
/* 删除掉已经执行过的,且不再需要执行的定时器 */ if (te->id == AE_DELETED_EVENT_ID) { ...... // 调用 createTimeEvent 时候注册的 finalizer 方法,释放资源 if (te->finalizerProc) { te->finalizerProc(eventLoop, te->clientData); now = getMonotonicUs(); } zfree(te); te = next; continue; }
/* 这段注释有点意思,大家可以仔细读一读,体会下作者的良苦用心 * Make sure we don't process time events created by time events in * this iteration. Note that this check is currently useless: we always * add new timers on the head, however if we change the implementation * detail, this check may be useful again: we keep it here for future * defense. */ if (te->id > maxId) { te = te->next; continue; }
// 真正的处理逻辑,调用创建 timeEvent 时候注册的 handler if (te->when <= now) { int retval;
id = te->id; te->refcount++; retval = te->timeProc(eventLoop, id, te->clientData); te->refcount--; processed++; now = getMonotonicUs();
// 定时器内容处理完后,会返回一个 int 值,表示下次执行需要等待的时间(秒) // 如果是 AE_NOMORE=-1,则表示不需要在执行了,下个 eventloop 会从链表删除掉该节点 if (retval != AE_NOMORE) { te->when = now + retval * 1000; } else { te->id = AE_DELETED_EVENT_ID; } } te = te->next; } return processed; }
其中一段注释非常有意思,”we keep it here for future defense” 这应该是一个优秀的工程师应该具备的基本素养之一。