redis的文件事件:即与io相关的事件。

/* File event structure */
typedef struct aeFileEvent {
int mask; /* one of AE_(READABLE|WRITABLE) */
aeFileProc *rfileProc; //读网络数据处理函数
aeFileProc *wfileProc; //写网络数据处理函数
void *clientData;
} aeFileEvent;

所有的文件事件放在aeEventLoop的数组中:

/* State of an event based program */
typedef struct aeEventLoop {
int maxfd; /* highest file descriptor currently registered */
int setsize; /* max number of file descriptors tracked */
long long timeEventNextId;
time_t lastTime; /* Used to detect system clock skew */
aeFileEvent *events; /* Registered events */
aeFiredEvent *fired; /* Fired events */
aeTimeEvent *timeEventHead;
int stop;
void *apidata; /* This is used for polling API specific data */
aeBeforeSleepProc *beforesleep;
aeBeforeSleepProc *aftersleep;
} aeEventLoop;

重点关注 events数组和fired数组,在(server.c) initServer中创建事件循环,

server.el = aeCreateEventLoop(server.maxclients+CONFIG_FDSET_INCR);

在(ae.c) aeCreateEventLoop中,为events数组和fired数组分配内存:

aeEventLoop *aeCreateEventLoop(int setsize) {
aeEventLoop *eventLoop;
int i; if ((eventLoop = zmalloc(sizeof(*eventLoop))) == NULL) goto err;
eventLoop->events = zmalloc(sizeof(aeFileEvent)*setsize);
eventLoop->fired = zmalloc(sizeof(aeFiredEvent)*setsize);
if (eventLoop->events == NULL || eventLoop->fired == NULL) goto err;
eventLoop->setsize = setsize;
eventLoop->lastTime = time(NULL);
eventLoop->timeEventHead = NULL;
eventLoop->timeEventNextId = 0;
eventLoop->stop = 0;
eventLoop->maxfd = -1;
eventLoop->beforesleep = NULL;
eventLoop->aftersleep = NULL;
if (aeApiCreate(eventLoop) == -1) goto err;
/* Events with mask == AE_NONE are not set. So let's initialize the
* vector with it. */
for (i = 0; i < setsize; i++)
eventLoop->events[i].mask = AE_NONE;
return eventLoop; err:
if (eventLoop) {
zfree(eventLoop->events);
zfree(eventLoop->fired);
zfree(eventLoop);
}
return NULL;
}

在aeCreateFileEvent中为events的具体元素赋值,由创建客户端连接进入aeCreateFileEvent方法的调用栈如下:

// 省略其他代码
client *createClient(int fd) {
client *c = zmalloc(sizeof(client)); /* passing -1 as fd it is possible to create a non connected client.
* This is useful since all the commands needs to be executed
* in the context of a client. When commands are executed in other
* contexts (for instance a Lua script) we need a non connected client. */
if (fd != -) {
anetNonBlock(NULL,fd);
anetEnableTcpNoDelay(NULL,fd);
if (server.tcpkeepalive)
anetKeepAlive(NULL,fd,server.tcpkeepalive);
if (aeCreateFileEvent(server.el,fd,AE_READABLE,
readQueryFromClient, c) == AE_ERR)
{
close(fd);
zfree(c);
return NULL;
}
} ...
return c;
}

把rfileProc和wfileProc的值设为readQueryFromClient函数

int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
aeFileProc *proc, void *clientData)
{
if (fd >= eventLoop->setsize) {
errno = ERANGE;
return AE_ERR;
}
aeFileEvent *fe = &eventLoop->events[fd]; if (aeApiAddEvent(eventLoop, fd, mask) == -)
return AE_ERR;
fe->mask |= mask;
if (mask & AE_READABLE) fe->rfileProc = proc;
if (mask & AE_WRITABLE) fe->wfileProc = proc;
fe->clientData = clientData;
if (fd > eventLoop->maxfd)
eventLoop->maxfd = fd;
return AE_OK;
}

当客户端发生网络IO时:

调用epoll_wait,获取发生事件的文件描述符,设置在fired元素中:

static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
aeApiState *state = eventLoop->apidata;
int retval, numevents = ; retval = epoll_wait(state->epfd,state->events,eventLoop->setsize,
tvp ? (tvp->tv_sec* + tvp->tv_usec/) : -);
if (retval > ) {
int j; numevents = retval;
for (j = ; j < numevents; j++) {
int mask = ;
struct epoll_event *e = state->events+j; if (e->events & EPOLLIN) mask |= AE_READABLE;
if (e->events & EPOLLOUT) mask |= AE_WRITABLE;
if (e->events & EPOLLERR) mask |= AE_WRITABLE;
if (e->events & EPOLLHUP) mask |= AE_WRITABLE;
eventLoop->fired[j].fd = e->data.fd;
eventLoop->fired[j].mask = mask;
}
}
return numevents;
}

在aeProcessEvents方法中,根据fired元素中的fd,处理IO事件。

for (j = ; j < numevents; j++) {
aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];
int mask = eventLoop->fired[j].mask;
int fd = eventLoop->fired[j].fd;
int rfired = ; /* note the fe->mask & mask & ... code: maybe an already processed
* event removed an element that fired and we still didn't
* processed, so we check if the event is still valid. */
if (fe->mask & mask & AE_READABLE) {
rfired = ;
fe->rfileProc(eventLoop,fd,fe->clientData,mask);
}
if (fe->mask & mask & AE_WRITABLE) {
if (!rfired || fe->wfileProc != fe->rfileProc)
fe->wfileProc(eventLoop,fd,fe->clientData,mask);
}
processed++;
}

最新文章

  1. ViewStub源码分析
  2. stm32cube--ADC单次转换
  3. 仿造w3school的试一试功能,实现左侧编辑框,右侧效果页面
  4. python特殊函数 __call__()
  5. C# Json时间类型的转换
  6. ObjectInputStream ObjectOutStream
  7. jmeter压测app
  8. Sql server 数据库中,纯SQL语句查询、执行 单引号问题。
  9. 跟着刚哥梳理java知识点——异常(十一)
  10. Lavarel artisan 命令
  11. ubuntu16.04安装交叉编译链
  12. 测者的测试技术手册:自动化单元工具EvoSuie的代码覆盖报告
  13. U盘插入电脑3.0的口没有反应了,2.0的口就可以
  14. P2521 [HAOI2011]防线修建
  15. python查找字符串所有子串
  16. matlab图片 latex显示
  17. python访问百度地图接口并返回信息
  18. php apache
  19. Hibernate的getTransaction()和beginTransaction()
  20. WebService程序数据集之WSDL取数

热门文章

  1. window7安装python的xgboost库方法
  2. 【Python】【jupyter-notebook】
  3. OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x0000000083e80000, 1366294528, 0) failed;
  4. rtrim
  5. python中enumerate内置库的使用
  6. 重装win7系统并激活
  7. 如何看待Arcsoft虹软,推出的人脸认知引擎免费SDK?
  8. HDU 3949 XOR
  9. xlua 实现协程替换Unity中的协程
  10. Linux-Ubuntu16.0.4相关命令