redis源码epoll用法
生活随笔
收集整理的這篇文章主要介紹了
redis源码epoll用法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
? ? ? ? ? ?學一下redis源碼中epoll的使用,由于功力有限不足之處望大家指正。
/** 創建一個新的 epoll 實例,并將它賦值給 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;}// 創建 epoll 實例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; } /** 事件狀態*/ typedef struct aeApiState {// epoll_event 實例描述符int epfd;// 事件槽struct epoll_event *events;} aeApiState; /* State of an event based program ** 事件處理器的狀態*/ typedef struct aeEventLoop {// 目前已注冊的最大描述符int maxfd; /* highest file descriptor currently registered */// 目前已追蹤的最大描述符int setsize; /* max number of file descriptors tracked */// 用于生成時間事件 idlong 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;} aeEventLoop;aeApiCreate函數為epoll_event分配空間,epoll_create創建一個epoll句柄,參數size用來告訴內核監聽的文件描述符的個數,epoll句柄就是函數的返回值。該返回值保存在aeEventLoop的apidata里面。
/** 關聯給定事件到 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 沒有關聯任何事件,那么這是一個 ADD 操作。** 如果已經關聯了某個/某些事件,那么這是一個 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是事件注冊函數,注冊要監聽的事件類型。state->epfd是epoll_create的返回值,op表示動作,EPOLL_CTL_ADD:注冊新的fd到epfd中;EPOLL_CTL_MOD:修改已經注冊的fd的監聽事件;EPOLL_CTL_DEL:從epfd中刪除一個fd;第三個參數是需要監聽的fd,第四個參數是告訴內核需要監聽什么事。通信每過一個階段,監聽事件的狀態也會發生改變,通過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 */ }; /** 獲取可執行事件*/ 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用于向用戶進程返回ready list// 有至少一個事件就緒?if (retval > 0) {int j;// 為已就緒事件設置相應的模式// 并加入到 eventLoop 的 fired 數組中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;}}// 返回已就緒事件個數return numevents; }epoll_wait等待事件的產生參數events用來從內核得到事件的集合,setsize告之內核這個events有多大,這個 maxevents的值不能大于創建epoll_create()時的size,參數tvp是超時時間。
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的redis源码epoll用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: redis源码客户端和服务端通信过程
- 下一篇: wireshark抓包数据学习