muduo源码分析之Poller

相关文件

muduo/net/Poller.h
muduo/net/Poller.cc
muduo/net/poller/*

作用

Poller是对IO多路复用的封装,在muduo中支持poll和epoll两种IO multiplexing机制。
Poller是EventLoop的间接成员,EventLoop调用其poll()函数获得当前活动的IO事件。
image

Poller源码分析

前面说到在muduo中支持poll和epoll两种IO multiplexing机制。
在muduo中Poller是虚基类,也是muduo中唯一使用面向对象编程方法的地方。
在muduo/net/poller/文件夹下,PollPoller是poll的封装,EpollPoller是epoll的封装,都继承了Poller。

Poller虚基类

Poller.h

/// Base class for IO Multiplexing
///
/// This class doesn't own the Channel objects.
class Poller : noncopyable
{
 public:
  typedef std::vector<Channel*> ChannelList;

  Poller(EventLoop* loop);
  virtual ~Poller();

  /// Polls the I/O events.
  /// Must be called in the loop thread.
  virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels) = 0;

  /// Changes the interested I/O events.
  /// Must be called in the loop thread.
  virtual void updateChannel(Channel* channel) = 0;

  /// Remove the channel, when it destructs.
  /// Must be called in the loop thread.
  virtual void removeChannel(Channel* channel) = 0;

  virtual bool hasChannel(Channel* channel) const;

  static Poller* newDefaultPoller(EventLoop* loop);

  void assertInLoopThread() const
  {
    ownerLoop_->assertInLoopThread();
  }

 protected:
  typedef std::map<int, Channel*> ChannelMap; //fd,channel
  ChannelMap channels_;

 private:
  EventLoop* ownerLoop_;
};

PollPoller子类

PollPoller.h

class PollPoller : public Poller
{
 public:

  PollPoller(EventLoop* loop);
  ~PollPoller() override;

  Timestamp poll(int timeoutMs, ChannelList* activeChannels) override;
  void updateChannel(Channel* channel) override;
  void removeChannel(Channel* channel) override;

 private:
  void fillActiveChannels(int numEvents,
                          ChannelList* activeChannels) const;

  typedef std::vector<struct pollfd> PollFdList;
  PollFdList pollfds_;
};

poll监听事件

PollPoller调用poll监听pollfds的事件

imestamp 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";
    fillActiveChannels(numEvents, activeChannels);//添加到活跃通道
  }
  else if (numEvents == 0)
  {
    LOG_TRACE << " nothing happened";
  }
  else
  {
    if (savedErrno != EINTR)
    {
      errno = savedErrno;
      LOG_SYSERR << "PollPoller::poll()";
    }
  }
  return now;
}

添加活跃通道

承接上面的poll函数,监听到活跃事件。将有活跃事件的通道添加到EventLoop的活跃通道列表

void PollPoller::fillActiveChannels(int numEvents,
                                    ChannelList* activeChannels) const
{
  //遍历文件描述符
  for (PollFdList::const_iterator pfd = pollfds_.begin();
      pfd != pollfds_.end() && numEvents > 0; ++pfd)
  {
  	//如果有活跃事件
    if (pfd->revents > 0)
    {
      --numEvents;
	  //找到fd对应的channel
      ChannelMap::const_iterator ch = channels_.find(pfd->fd);
      assert(ch != channels_.end());
      Channel* channel = ch->second; //channels_的key是fd, value是Channel*
      assert(channel->fd() == pfd->fd);
      channel->set_revents(pfd->revents); //设置通道的
      // pfd->revents = 0;
      activeChannels->push_back(channel);//添加到EventLoop的活跃通道列表
    }
  }
}

更新通道

先看一个通道更新的传递链:
Channel::enableReading()->Channel::update()->EventLoop::updateChannel()->PollPoller::updateChannel()
image
一个通道修改了自身监听的event后,调用update让Poller更新监听的事件。
Poller则根据Channel的events修改pollfd中的events。

void PollPoller::updateChannel(Channel* channel)
{
  Poller::assertInLoopThread();
  LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events();
  if (channel->index() < 0) //新的Channel
  {
    // a new one, add to pollfds_
    assert(channels_.find(channel->fd()) == channels_.end());
    struct pollfd pfd;
    pfd.fd = channel->fd();
    pfd.events = static_cast<short>(channel->events());
    pfd.revents = 0;
    pollfds_.push_back(pfd);  //添加到pollfds
    int idx = static_cast<int>(pollfds_.size())-1;
    channel->set_index(idx);
    channels_[pfd.fd] = channel; //添加到Poller的map
  }
  else
  {
    // update existing one 更新已存在的Channel
    assert(channels_.find(channel->fd()) != channels_.end());
    assert(channels_[channel->fd()] == channel);
    int idx = channel->index();
    assert(0 <= idx && idx < static_cast<int>(pollfds_.size()));
    struct pollfd& pfd = pollfds_[idx];
    assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1);
    pfd.fd = channel->fd();
    pfd.events = static_cast<short>(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();
  assert(channels_.find(channel->fd()) != channels_.end());
  assert(channels_[channel->fd()] == channel);
  assert(channel->isNoneEvent());
  int idx = channel->index();
  assert(0 <= idx && idx < static_cast<int>(pollfds_.size()));
  const struct pollfd& pfd = pollfds_[idx]; (void)pfd;
  assert(pfd.fd == -channel->fd()-1 && pfd.events == channel->events());
  size_t n = channels_.erase(channel->fd());
  assert(n == 1); (void)n;
  if (implicit_cast<size_t>(idx) == pollfds_.size()-1)
  {
    pollfds_.pop_back();
  }
  else
  {
    int channelAtEnd = pollfds_.back().fd;
    iter_swap(pollfds_.begin()+idx, pollfds_.end()-1);
    if (channelAtEnd < 0)
    {
      channelAtEnd = -channelAtEnd-1;
    }
    channels_[channelAtEnd]->set_index(idx);
    pollfds_.pop_back();
  }
}
posted @ 2021-05-16 19:30  零十  阅读(180)  评论(0编辑  收藏  举报