net3. Reactor关键结构——Poller轮询器类

Poller类图
在这里插入图片描述
Poller类

  1. Poller是一个抽象类,Poller是对I/O复用的抽象,有两个派生类PollPoller和EPollPoller,一个EventLoop包含一个Poller对象。
  2. PollPoller和EPollPoller使用一个map来存放描述符fd和对应的Channel类型的指针,这样我们就可以通过fd很方便的得到Channel了。

1.Poller类

数据成员:

EventLoop* ownerLoop_:Poller所属EventLoop

typedef

typedef std::vector<Channel*> ChannelList

成员函数:

Poller(EventLoop* loop):构造函数,记录Poller所属EventLoop
virtual ~Poller():析构函数
virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels) = 0:poll()填充活动通道的列表activeChannels,返回当前时间
virtual void updateChannel(Channel* channel) = 0:updateChannel()用于注册或者更新通道所关注的事件
virtual void removeChannel(Channel* channel) = 0:removeChannel()用于移除通道所关注的事件
static Poller* newDefaultPoller(EventLoop* loop):在DefaultPoller.cc生成PollPoller类或者EPollPoller类
void assertInLoopThread():断言当前处于创建该对象的线程中

Poller.h

#ifndef MUDUO_NET_POLLER_H
#define MUDUO_NET_POLLER_H

#include <vector>
#include <boost/noncopyable.hpp>

#include <muduo/base/Timestamp.h>
#include <muduo/net/EventLoop.h>

namespace muduo
{
namespace net
{

class Channel;

///
/// Base class for IO Multiplexing
///
/// This class doesn't own the Channel objects.
class Poller : boost::noncopyable
{
 public:
  typedef std::vector<Channel*> ChannelList;
  
  //构造函数记录Poller所属EventLoop
  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;

  static Poller* newDefaultPoller(EventLoop* loop);
  //断言当前处于创建该对象的线程中
  void assertInLoopThread()
  {
    ownerLoop_->assertInLoopThread();
  }

 private:
 // Poller所属EventLoop 
 EventLoop* ownerLoop_;	
};

}
}
#endif  // MUDUO_NET_POLLER_H

Poller.cc

#include <muduo/net/Poller.h>

using namespace muduo;
using namespace muduo::net;

Poller::Poller(EventLoop* loop)
  : ownerLoop_(loop)
{
}

Poller::~Poller()
{
}


DefaultPoller.cc

#include <muduo/net/Poller.h>
#include <muduo/net/poller/PollPoller.h>
#include <muduo/net/poller/EPollPoller.h>

#include <stdlib.h>

using namespace muduo::net;

//生成PollPoller类或者EPollPoller类
Poller* Poller::newDefaultPoller(EventLoop* loop)
{  //实际上生成的是EPollPoller类型的对象
  if (::getenv("MUDUO_USE_POLL"))
  {
    return new PollPoller(loop);
  }
  else
  {
    return new EPollPoller(loop);
  }
}

2.PollPoller类

数据成员:

PollFdList pollfds_:所关注的文件描述符列表pollfds_
ChannelMap channels_:所关注的通道列表channels_,由fd对应channel

typedef

typedef std::vector PollFdList;
typedef std::map<int, Channel*> ChannelMap;

成员函数:

PollPoller(EventLoop* loop):构造函数,调用Poller类的构造函数Poller(loop)初始化Poller所属EventLoop,即ownerLoop_
virtual ~PollPoller():析构函数
virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels):poll()获得当前活动的IO事件,填充活动通道的列表activeChannels,并返回当前时间
virtual void updateChannel(Channel* channel):updateChannel()的主要功能是负责维护和更新pollfds_,用于注册或者更新通道所关注的事件
virtual void removeChannel(Channel* channel):removeChannel()用于移除通道所关注的事件
void fillActiveChannels(int numEvents, ChannelList* activeChannels) const:poll()调用fillActiveChannels(),在activeChannels中放入numEvents个活动通道

PollPoller.h

#ifndef MUDUO_NET_POLLER_POLLPOLLER_H
#define MUDUO_NET_POLLER_POLLPOLLER_H

#include <muduo/net/Poller.h>

#include <map>
#include <vector>

struct pollfd;

namespace muduo
{
namespace net
{

///
/// IO Multiplexing with poll(2).
///
class PollPoller : public Poller
{
 public:

  PollPoller(EventLoop* loop);
  virtual ~PollPoller();
  
  //poll()填充活动通道的列表activeChannels,返回当前时间
  virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels);
  //updateChannel()用于注册或者更新通道所关注的事件
  virtual void updateChannel(Channel* channel);
  //removeChannel()用于移除通道所关注的事件
  virtual void removeChannel(Channel* channel);

 private:
  //poll()调用fillActiveChannels(),在activeChannels中放入numEvents个活动通道
  void fillActiveChannels(int numEvents,
                          ChannelList* activeChannels) const;
  //vector类型的PollFdList,存储pollfd类型的结构数组
  typedef std::vector<struct pollfd> PollFdList;
  //ChannelMap类型中key是文件描述符,value是Channel*
  typedef std::map<int, Channel*> ChannelMap;	
  //文件描述符列表pollfds_
  PollFdList pollfds_;
  //所关注的通道列表channels_
  ChannelMap channels_;
};

}
}
#endif  // MUDUO_NET_POLLER_POLLPOLLER_H

PollPoller.cc

#include <muduo/net/poller/PollPoller.h>

#include <muduo/base/Logging.h>
#include <muduo/base/Types.h>
#include <muduo/net/Channel.h>

#include <assert.h>
#include <poll.h>

using namespace muduo;
using namespace muduo::net;

PollPoller::PollPoller(EventLoop* loop)
  : Poller(loop)
{
}

PollPoller::~PollPoller()
{
}

Timestamp PollPoller::poll(int timeoutMs, ChannelList* activeChannels)
{
  //调用标准的::poll
  int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs);
  Timestamp now(Timestamp::now());
  if (numEvents > 0)
  {
    LOG_TRACE << numEvents << " events happended";
    fillActiveChannels(numEvents, activeChannels);
  }
  else if (numEvents == 0)
  {
    LOG_TRACE << " nothing happended";
  }
  else
  {
    LOG_SYSERR << "PollPoller::poll()";
  }
  return now;
}

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;
      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();
  // index < 0说明是一个新的通道
  // a new one, add to pollfds_
  if (channel->index() < 0)
  {
    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);
    int idx = static_cast<int>(pollfds_.size())-1;
    channel->set_index(idx);
    channels_[pfd.fd] = 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);
    pfd.events = static_cast<short>(channel->events());
    pfd.revents = 0;
	// 将一个通道暂时更改为不关注事件,但不从Poller中移除该通道
    if (channel->isNoneEvent())
    {
      // ignore this pollfd
	  // 暂时忽略该文件描述符的事件
	  // 这里pfd.fd 可以直接设置为-1
      pfd.fd = -channel->fd()-1;	// 这样子设置是为了removeChannel优化
    }
  }
}

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
  {
	// 这里移除的算法复杂度是O(1),将待删除元素与最后一个元素交换再pop_back
    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();
  }
}

3.EPollPoller类

数据成员:

static const int kInitEventListSize = 16:能够容纳的事件个数
int epollfd_:epoll_create()的返回值
EventList events_:事件列表events_
ChannelMap channels_:所关注的通道列表channels_

typedef

typedef std::vector EventList;
typedef std::map<int, Channel*> ChannelMap;

成员函数:

EPollPoller(EventLoop* loop):构造函数,调用Poller类的构造函数Poller(loop)初始化Poller所属EventLoop,即ownerLoop_
virtual ~EPollPoller():析构函数
virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels):poll()填充活动通道的列表activeChannels,返回当前时间
virtual void updateChannel(Channel* channel):updateChannel()用于注册或者更新通道所关注的事件
virtual void removeChannel(Channel* channel):removeChannel()用于移除通道所关注的事件
void fillActiveChannels(int numEvents,ChannelList* activeChannels) const:poll()调用fillActiveChannels(),在activeChannels中放入numEvents个活动通道
void update(int operation, Channel* channel):updateChannel()调用update()注册或者更新通道所关注的事件

EPollPoller.h

#ifndef MUDUO_NET_POLLER_EPOLLPOLLER_H
#define MUDUO_NET_POLLER_EPOLLPOLLER_H

#include <muduo/net/Poller.h>

#include <map>
#include <vector>

struct epoll_event;

namespace muduo
{
namespace net
{

///
/// IO Multiplexing with epoll(4).
///
class EPollPoller : public Poller
{
 public:
  EPollPoller(EventLoop* loop);
  virtual ~EPollPoller();
  
  //poll()填充活动通道的列表activeChannels,返回当前时间
  virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels);
  //updateChannel()用于注册或者更新通道所关注的事件
  virtual void updateChannel(Channel* channel);
  //removeChannel()用于移除通道所关注的事件
  virtual void removeChannel(Channel* channel);

 private:
  //能够容纳的事件个数
  static const int kInitEventListSize = 16;
  
  //poll()调用fillActiveChannels(),在activeChannels中放入numEvents个活动通道
  void fillActiveChannels(int numEvents,
                          ChannelList* activeChannels) const;
  //updateChannel()调用update()注册或者更新通道所关注的事件
  void update(int operation, Channel* channel);

  typedef std::vector<struct epoll_event> EventList;
  typedef std::map<int, Channel*> ChannelMap;
  
  //epoll_create()的返回值
  int epollfd_;
  //事件列表events_
  EventList events_;
  //所关注的通道列表channels_
  ChannelMap channels_;
};

}
}
#endif  // MUDUO_NET_POLLER_EPOLLPOLLER_H

EPollPoller.cc

#include <muduo/net/poller/EPollPoller.h>

#include <muduo/base/Logging.h>
#include <muduo/net/Channel.h>

#include <boost/static_assert.hpp>

#include <assert.h>
#include <errno.h>
#include <poll.h>
#include <sys/epoll.h>

using namespace muduo;
using namespace muduo::net;

// On Linux, the constants of poll(2) and epoll(4)
// are expected to be the same.
BOOST_STATIC_ASSERT(EPOLLIN == POLLIN);
BOOST_STATIC_ASSERT(EPOLLPRI == POLLPRI);
BOOST_STATIC_ASSERT(EPOLLOUT == POLLOUT);
BOOST_STATIC_ASSERT(EPOLLRDHUP == POLLRDHUP);
BOOST_STATIC_ASSERT(EPOLLERR == POLLERR);
BOOST_STATIC_ASSERT(EPOLLHUP == POLLHUP);

namespace
{
const int kNew = -1;
const int kAdded = 1;
const int kDeleted = 2;
}

EPollPoller::EPollPoller(EventLoop* loop)
  : Poller(loop),
    epollfd_(::epoll_create1(EPOLL_CLOEXEC)),
    events_(kInitEventListSize)
{
  if (epollfd_ < 0)
  {
    LOG_SYSFATAL << "EPollPoller::EPollPoller";
  }
}

EPollPoller::~EPollPoller()
{
  ::close(epollfd_);
}

Timestamp EPollPoller::poll(int timeoutMs, ChannelList* activeChannels)
{
  int numEvents = ::epoll_wait(epollfd_,
                               &*events_.begin(),
                               static_cast<int>(events_.size()),
                               timeoutMs);
  Timestamp now(Timestamp::now());
  if (numEvents > 0)
  {
    LOG_TRACE << numEvents << " events happended";
    fillActiveChannels(numEvents, activeChannels);
    if (implicit_cast<size_t>(numEvents) == events_.size())
    {
      events_.resize(events_.size()*2);
    }
  }
  else if (numEvents == 0)
  {
    LOG_TRACE << " nothing happended";
  }
  else
  {
    LOG_SYSERR << "EPollPoller::poll()";
  }
  return now;
}

void EPollPoller::fillActiveChannels(int numEvents,
                                     ChannelList* activeChannels) const
{
  assert(implicit_cast<size_t>(numEvents) <= events_.size());
  for (int i = 0; i < numEvents; ++i)
  {
    Channel* channel = static_cast<Channel*>(events_[i].data.ptr);
#ifndef NDEBUG
    int fd = channel->fd();
    ChannelMap::const_iterator it = channels_.find(fd);
    assert(it != channels_.end());
    assert(it->second == channel);
#endif
    channel->set_revents(events_[i].events);
    activeChannels->push_back(channel);
  }
}

void EPollPoller::updateChannel(Channel* channel)
{
  Poller::assertInLoopThread();
  LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events();
  const int index = channel->index();
  if (index == kNew || index == kDeleted)
  {
    // a new one, add with EPOLL_CTL_ADD
    int fd = channel->fd();
    if (index == kNew)
    {
      assert(channels_.find(fd) == channels_.end());
      channels_[fd] = channel;
    }
    else // index == kDeleted
    {
      assert(channels_.find(fd) != channels_.end());
      assert(channels_[fd] == channel);
    }
    channel->set_index(kAdded);
    update(EPOLL_CTL_ADD, channel);
  }
  else
  {
    // update existing one with EPOLL_CTL_MOD/DEL
    int fd = channel->fd();
    (void)fd;
    assert(channels_.find(fd) != channels_.end());
    assert(channels_[fd] == channel);
    assert(index == kAdded);
    if (channel->isNoneEvent())
    {
      update(EPOLL_CTL_DEL, channel);
      channel->set_index(kDeleted);
    }
    else
    {
      update(EPOLL_CTL_MOD, channel);
    }
  }
}

void EPollPoller::removeChannel(Channel* channel)
{
  Poller::assertInLoopThread();
  int fd = channel->fd();
  LOG_TRACE << "fd = " << fd;
  assert(channels_.find(fd) != channels_.end());
  assert(channels_[fd] == channel);
  assert(channel->isNoneEvent());
  int index = channel->index();
  assert(index == kAdded || index == kDeleted);
  size_t n = channels_.erase(fd);
  (void)n;
  assert(n == 1);

  if (index == kAdded)
  {
    update(EPOLL_CTL_DEL, channel);
  }
  channel->set_index(kNew);
}

void EPollPoller::update(int operation, Channel* channel)
{
  struct epoll_event event;
  bzero(&event, sizeof event);
  event.events = channel->events();
  event.data.ptr = channel;
  int fd = channel->fd();
  if (::epoll_ctl(epollfd_, operation, fd, &event) < 0)
  {
    if (operation == EPOLL_CTL_DEL)
    {
      LOG_SYSERR << "epoll_ctl op=" << operation << " fd=" << fd;
    }
    else
    {
      LOG_SYSFATAL << "epoll_ctl op=" << operation << " fd=" << fd;
    }
  }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值