本文共 4738 字,大约阅读时间需要 15 分钟。
//监听事件的函数,返回一个事件就绪的事件 virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels) = 0; /// Changes the interested I/O events. /// Must be called in the loop thread. //实现为纯虚函数,在PollPoller或EPollPoller 中实现 //更新所监听的事件 virtual void updateChannel(Channel* channel) = 0; /// Remove the channel, when it destructs. /// Must be called in the loop thread. //删除一个Channel virtual void removeChannel(Channel* channel) = 0;
typedef std::vectorPollFdList; PollFdList pollfds_; //struct pollfd 的数组,存放所有监听的文件描述符以及事件
Timestamp PollPoller::poll(int timeoutMs, ChannelList* activeChannels){ // XXX pollfds_ shouldn't change //待处理事件的数量,在此处监听 int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); int savedErrno = errno; //记录事件产生的事件,便于下次定时器的跟新 Timestamp now(Timestamp::now()); //有就绪事件产生 if (numEvents > 0) { LOG_TRACE << numEvents << " events happened"; //将所有有事件发生的文件描述符所对应的Channle 放到activeChannels中 fillActiveChannels(numEvents, activeChannels); } //事件超时 else if (numEvents == 0) { LOG_TRACE << " nothing happened"; } //产生错误 else { if (savedErrno != EINTR) { errno = savedErrno; LOG_SYSERR << "PollPoller::poll()"; } } return now;}
void PollPoller::fillActiveChannels(int numEvents, ChannelList* activeChannels) const{ //依次取出就绪的事件的channel for (PollFdList::const_iterator pfd = pollfds_.begin(); pfd != pollfds_.end() && numEvents > 0; ++pfd) { //如果当前的channel 上有事件产生 if (pfd->revents > 0) { --numEvents; ChannelMap::const_iterator ch = channels_.find(pfd->fd); assert(ch != channels_.end()); Channel* channel = ch->second; assert(channel->fd() == pfd->fd); //设置该文件描述符上的事件 //该函数不做处理,只设置到达的事件 channel->set_revents(pfd->revents); // pfd->revents = 0; activeChannels->push_back(channel); } }}
void PollPoller::updateChannel(Channel* channel){ Poller::assertInLoopThread(); //记录日志 LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events(); //如果channel->index() < 0 表示新添加一个Channel if (channel->index() < 0) { // a new one, add to pollfds_ assert(channels_.find(channel->fd()) == channels_.end()); struct pollfd pfd; //非阻塞IO 注册 pfd.fd = channel->fd(); //新产生的文件描述符 pfd.events = static_cast(channel->events()); pfd.revents = 0; //每次循环监听都会从pollfds_中读取需要监听的文件描述符, //所以添加到pollfds_之后下次循环就会监听 pollfds_.push_back(pfd); int idx = static_cast (pollfds_.size())-1; channel->set_index(idx); //用于管理所有的Channel 对象 channels_[pfd.fd] = channel; } //表示该Channel 已经存在,更新监听的事件 else { // update existing one assert(channels_.find(channel->fd()) != channels_.end()); assert(channels_[channel->fd()] == channel); int idx = channel->index(); assert(0 <= idx && idx < static_cast (pollfds_.size())); struct pollfd& pfd = pollfds_[idx]; assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1); //更新已经存在的Channel pfd.fd = channel->fd(); pfd.events = static_cast (channel->events()); pfd.revents = 0; if (channel->isNoneEvent()) { // ignore this pollfd pfd.fd = -channel->fd()-1; } }}
void PollPoller::removeChannel(Channel* channel){ Poller::assertInLoopThread(); LOG_TRACE << "fd = " << channel->fd(); //断言当前的Channel 已经存在 assert(channels_.find(channel->fd()) != channels_.end()); //断言channels_ 存在的Channel 与 要删除的Channel 一致 assert(channels_[channel->fd()] == channel); //断言当前的channel 没有要监听的事件 assert(channel->isNoneEvent()); int idx = channel->index(); assert(0 <= idx && idx < static_cast (pollfds_.size())); const struct pollfd& pfd = pollfds_[idx]; (void)pfd; assert(pfd.fd == -channel->fd()-1 && pfd.events == channel->events()); //删除一个Channel size_t n = channels_.erase(channel->fd()); assert(n == 1); (void)n; if (implicit_cast(idx) == pollfds_.size()-1) { pollfds_.pop_back(); } else { int channelAtEnd = pollfds_.back().fd; //idx 文件描述符在vector中的位置 //将最后一个文件描述符与要删除的为文件描述符交换, //消除了删除一个元素的数据移动带来的开销 iter_swap(pollfds_.begin()+idx, pollfds_.end()-1); if (channelAtEnd < 0) { channelAtEnd = -channelAtEnd-1; } //重新设置最后一个文件描述符的index channels_[channelAtEnd]->set_index(idx); //删除一个文件描述符 pollfds_.pop_back(); }}
typedef std::vectorEventList; int epollfd_; //epoll下用于监听其他文件描述符的文件描述符 EventList events_; //监听的事件列表
关于EpollPoller 的 poll 、updateChannel 、removeChannel ,功能与PollPoller 的一样,实现的内部函数不同,这里不作介绍。
转载地址:http://ianwi.baihongyu.com/