负责监听文件描述符事件是否触发以及返回发生事件的文件描述符以及具体事件的模块就是Poller,所以一个Poller对象对应一个事件监听器。
class Epoll { public: Epoll(); ~Epoll(); void epoll_add(const sp_Channel& request); void epoll_mod(const sp_Channel& request); void epoll_del(const sp_Channel& request); void poll(std::vector<sp_Channel>& req); private: int epollFd_; std::vector<epoll_event> events_; // epoll_wait()返回的活动事件都放在这个数组 ⾥ std::unordered_map<int, sp_Channel> channelMap_; };
- Poller/EpollPoller的重要成员变量
- epollfd_: 就是用epoll_create方法返回的epoll句柄,这个是常识。
- channels_:这个变量是std::unordered_map<int, Channel*>类型,负责记录 文件描述符 —> Channel的映射,也帮忙保管所有- 注册在你这个Poller上的Channel。
- ownerLoop_:所属的EventLoop对象,看到后面你懂了。
其他函数⽆⾮就是对 Epoll_ctl(4) 和 Epoll_wait(4) 的封装。
void Epoll::poll(std::vector<sp_Channel>& req) { int event_count = Epoll_wait(epollFd_, &*events_.begin(), events_.size(), EPOLLWAIT_TIME); for(int i = 0; i < event_count; ++i) { int fd = events_[i].data.fd; sp_Channel temp = channelMap_[fd]; temp->setRevents(events_[i].events); req.emplace_back(std::move(temp)); } // LOG << "Epoll finished"; }
Epoll::poll(1) 这个函数可以说是 Poller 的核⼼了,当外部调⽤ poll ⽅法的时候,该⽅法底层其实是通过 epoll_wait 获取这个事件监听器上发⽣事件的 fd 及其对应发⽣的事件,我们知道每个 fd 都是由⼀个 Channel 封 装的,通过哈希表 channelMap_ 可以根据 fd 找到封装这个 fd 的 Channel 。将 IO 多路复⽤模块监听到该 fd 发⽣ 的事件写进这个 Channel 中的 revents 成员变量中。然后把这个 Channel 装进 req 中。这样,当外界调⽤完 poll 之后就能拿到 IO 多路复⽤模块的 监听结果 ( std::vector<sp_Channel>& req )。