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 的一样,实现的内部函数不同,这里不作介绍。