muduo 源码分析底层IO类


muduo 底层IO类底层通过poll 和 epoll 来实现的,通过一个抽象类Poller 提供接口,PollPoller 和 EPollPoller来继承Poller 类

Poller

//监听事件的函数,返回一个事件就绪的事件
  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;

PollPoller

  typedef std::vector<struct pollfd> PollFdList;
  PollFdList pollfds_;  //struct pollfd 的数组,存放所有监听的文件描述符以及事件

poll

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;
}

fillActiveChannels

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);
    }
  }
}

updateChannel

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<short>(channel->events());
    pfd.revents = 0;
	//每次循环监听都会从pollfds_中读取需要监听的文件描述符,
	//所以添加到pollfds_之后下次循环就会监听
    pollfds_.push_back(pfd);
    int idx = static_cast<int>(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<int>(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<short>(channel->events());
    pfd.revents = 0;
    if (channel->isNoneEvent())
    {
      // ignore this pollfd
      pfd.fd = -channel->fd()-1;
    }
  }
}

remove

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<int>(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<size_t>(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();
  }
}

EPollPoller

  typedef std::vector<struct epoll_event> EventList;
  int epollfd_;		//epoll下用于监听其他文件描述符的文件描述符
  EventList events_;	//监听的事件列表

关于EpollPoller 的 poll 、updateChannel 、removeChannel ,功能与PollPoller 的一样,实现的内部函数不同,这里不作介绍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值