redis的文件事件
2024-08-27 08:11:51
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++;
}
最新文章
- ViewStub源码分析
- stm32cube--ADC单次转换
- 仿造w3school的试一试功能,实现左侧编辑框,右侧效果页面
- python特殊函数 __call__()
- C# Json时间类型的转换
- ObjectInputStream ObjectOutStream
- jmeter压测app
- Sql server 数据库中,纯SQL语句查询、执行 单引号问题。
- 跟着刚哥梳理java知识点——异常(十一)
- Lavarel artisan 命令
- ubuntu16.04安装交叉编译链
- 测者的测试技术手册:自动化单元工具EvoSuie的代码覆盖报告
- U盘插入电脑3.0的口没有反应了,2.0的口就可以
- P2521 [HAOI2011]防线修建
- python查找字符串所有子串
- matlab图片 latex显示
- python访问百度地图接口并返回信息
- php apache
- Hibernate的getTransaction()和beginTransaction()
- WebService程序数据集之WSDL取数
热门文章
- window7安装python的xgboost库方法
- 【Python】【jupyter-notebook】
- OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x0000000083e80000, 1366294528, 0) failed;
- rtrim
- python中enumerate内置库的使用
- 重装win7系统并激活
- 如何看待Arcsoft虹软,推出的人脸认知引擎免费SDK?
- HDU 3949 XOR
- xlua 实现协程替换Unity中的协程
- Linux-Ubuntu16.0.4相关命令