redis源码epoll用法
? ? ? ? ? ?學(xué)一下redis源碼中epoll的使用,由于功力有限不足之處望大家指正。
/** 創(chuàng)建一個新的 epoll 實(shí)例,并將它賦值給 eventLoop*/ static int aeApiCreate(aeEventLoop *eventLoop) {aeApiState *state = zmalloc(sizeof(aeApiState));if (!state) return -1;// 初始化事件槽空間state->events = zmalloc(sizeof(struct epoll_event)*eventLoop->setsize);if (!state->events) {zfree(state);return -1;}// 創(chuàng)建 epoll 實(shí)例state->epfd = epoll_create(1024); /* 1024 is just a hint for the kernel */if (state->epfd == -1) {zfree(state->events);zfree(state);return -1;}// 賦值給 eventLoopeventLoop->apidata = state;return 0; } /** 事件狀態(tài)*/ typedef struct aeApiState {// epoll_event 實(shí)例描述符int epfd;// 事件槽struct epoll_event *events;} aeApiState; /* State of an event based program ** 事件處理器的狀態(tài)*/ typedef struct aeEventLoop {// 目前已注冊的最大描述符int maxfd; /* highest file descriptor currently registered */// 目前已追蹤的最大描述符int setsize; /* max number of file descriptors tracked */// 用于生成時間事件 idlong long timeEventNextId;// 最后一次執(zhí)行時間事件的時間time_t lastTime; /* Used to detect system clock skew */// 已注冊的文件事件aeFileEvent *events; /* Registered events */// 已就緒的文件事件aeFiredEvent *fired; /* Fired events */// 時間事件aeTimeEvent *timeEventHead;// 事件處理器的開關(guān)int stop;// 多路復(fù)用庫的私有數(shù)據(jù)void *apidata; /* This is used for polling API specific data */// 在處理事件前要執(zhí)行的函數(shù)aeBeforeSleepProc *beforesleep;} aeEventLoop;aeApiCreate函數(shù)為epoll_event分配空間,epoll_create創(chuàng)建一個epoll句柄,參數(shù)size用來告訴內(nèi)核監(jiān)聽的文件描述符的個數(shù),epoll句柄就是函數(shù)的返回值。該返回值保存在aeEventLoop的apidata里面。
/** 關(guān)聯(lián)給定事件到 fd*/ static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {aeApiState *state = eventLoop->apidata;struct epoll_event ee;/* If the fd was already monitored for some event, we need a MOD* operation. Otherwise we need an ADD operation. ** 如果 fd 沒有關(guān)聯(lián)任何事件,那么這是一個 ADD 操作。** 如果已經(jīng)關(guān)聯(lián)了某個/某些事件,那么這是一個 MOD 操作。*/int op = eventLoop->events[fd].mask == AE_NONE ?EPOLL_CTL_ADD : EPOLL_CTL_MOD;// 注冊事件到 epollee.events = 0;mask |= eventLoop->events[fd].mask; /* Merge old events */if (mask & AE_READABLE) ee.events |= EPOLLIN;if (mask & AE_WRITABLE) ee.events |= EPOLLOUT;ee.data.u64 = 0; /* avoid valgrind warning */ee.data.fd = fd;if (epoll_ctl(state->epfd,op,fd,&ee) == -1) return -1;return 0; }epoll_ctl是事件注冊函數(shù),注冊要監(jiān)聽的事件類型。state->epfd是epoll_create的返回值,op表示動作,EPOLL_CTL_ADD:注冊新的fd到epfd中;EPOLL_CTL_MOD:修改已經(jīng)注冊的fd的監(jiān)聽事件;EPOLL_CTL_DEL:從epfd中刪除一個fd;第三個參數(shù)是需要監(jiān)聽的fd,第四個參數(shù)是告訴內(nèi)核需要監(jiān)聽什么事。通信每過一個階段,監(jiān)聽事件的狀態(tài)也會發(fā)生改變,通過epoll_ctl來改變。
typedef union epoll_data {void *ptr;int fd;__uint32_t u32;__uint64_t u64; } epoll_data_t;struct epoll_event {__uint32_t events; /* Epoll events */epoll_data_t data; /* User data variable */ }; /** 獲取可執(zhí)行事件*/ static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {printf("---------epoll aeApiPoll----------\n");aeApiState *state = eventLoop->apidata;int retval, numevents = 0;// 等待時間retval = epoll_wait(state->epfd,state->events,eventLoop->setsize,tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);//epoll_wait用于向用戶進(jìn)程返回ready list// 有至少一個事件就緒?if (retval > 0) {int j;// 為已就緒事件設(shè)置相應(yīng)的模式// 并加入到 eventLoop 的 fired 數(shù)組中numevents = retval;for (j = 0; j < numevents; j++) {int mask = 0;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;}}// 返回已就緒事件個數(shù)return numevents; }epoll_wait等待事件的產(chǎn)生參數(shù)events用來從內(nèi)核得到事件的集合,setsize告之內(nèi)核這個events有多大,這個 maxevents的值不能大于創(chuàng)建epoll_create()時的size,參數(shù)tvp是超時時間。
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的redis源码epoll用法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: redis源码客户端和服务端通信过程
- 下一篇: wireshark抓包数据学习