Channel是selectable IO channel,负责注册与响应IO 事件,它不拥有file descriptor。
Channel是Acceptor、Connector、EventLoop、TimerQueue、TcpConnection的成员,生命期由后者控制。
时序图
eventloop.h
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
//
// This is a public header file, it must only include public header files.
#ifndef MUDUO_NET_EVENTLOOP_H
#define MUDUO_NET_EVENTLOOP_H
#include
#include
#include
#include
#include
#include
namespace muduo
{
namespace net
{
class Channel; //聚合
class Poller; //组合
///
/// Reactor, at most one per thread.
///
/// This is an interface class, so don't expose too much details.
class EventLoop : boost::noncopyable
{
public:
EventLoop();
~EventLoop(); // force out-line dtor, for scoped_ptr members.
///
/// Loops forever.
///
/// Must be called in the same thread as creation of the object.
///
void loop();
void quit();
///
/// Time when poll returns, usually means data arrivial.
///
Timestamp pollReturnTime() const { return pollReturnTime_; }
// internal usage
void updateChannel(Channel* channel); // 在Poller中添加(注册)或者更新通道
void removeChannel(Channel* channel); // 从Poller中移除通道
/*断言是否在Loop 线程中*/
void assertInLoopThread()
{
//如果不是在LoopThread中,终止程序
if (!isInLoopThread())
{
abortNotInLoopThread();
}
}
//判断是在当前线程是否在LoopThread中
bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); }
static EventLoop* getEventLoopOfCurrentThread();
private:
void abortNotInLoopThread();
void printActiveChannels() const; // DEBUG
typedef std::vector ChannelList;
bool looping_; /*是否处于循环状态 atomic */
bool quit_; /*是否退出Loop atomic */
bool eventHandling_; /*当前是否处于事件处理的状态 atomic */
const pid_t threadId_; // 当前对象所属线程ID
Timestamp pollReturnTime_; //调用poller时候的返回时间
boost::scoped_ptr poller_; //poller对象,生命周期由EventLoop控制
ChannelList activeChannels_; // Poller返回的活动通道 ,
//就是活动状态的socket///typedef std::vector ChannelList;
Channel* currentActiveChannel_; // 当前正在处理的活动通道
};
}
}
#endif // MUDUO_NET_EVENTLOOP_H
EventLoop.cc
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
#include
#include
#include
#include
//#include
using namespace muduo;
using namespace muduo::net;
namespace
{
// 当前线程EventLoop对象指针
// 线程局部存储
__thread EventLoop* t_loopInThisThread = 0;
const int kPollTimeMs = 10000;
}
EventLoop* EventLoop::getEventLoopOfCurrentThread()
{
return t_loopInThisThread;
}
/*
事件循环,该函数不能夸线程调用
只能在创建该对象的线程中调用
**/
EventLoop::EventLoop()
: looping_(false),
quit_(false),
eventHandling_(false),
threadId_(CurrentThread::tid()),
poller_(Poller::newDefaultPoller(this)),
currentActiveChannel_(NULL)
{
LOG_TRACE << "EventLoop created " << this << " in thread " << threadId_;
// 如果当前线程已经创建了EventLoop对象,终止(LOG_FATAL)
if (t_loopInThisThread)
{
LOG_FATAL << "Another EventLoop " << t_loopInThisThread
<< " exists in this thread " << threadId_;
}
//如果当前线程没有创建EventLoop对象,则创建EventLoop对象,并且进行绑定
else
{
t_loopInThisThread = this;
}
}
EventLoop::~EventLoop()
{
t_loopInThisThread = NULL;
}
//这是IO线程
// 事件循环,该函数不能跨线程调用
// 只能在创建该对象的线程中调用
void EventLoop::loop()
{
//断言是否处于非循环状态
assert(!looping_);
// 断言当前处于创建该对象的线程中
assertInLoopThread();
looping_ = true;
LOG_TRACE << "EventLoop " << this << " start looping";
//::poll(NULL, 0, 5*1000);
//循环直到退出
while (!quit_)
{
//先清除活动通道
activeChannels_.clear();
//调用poller_->poll返回活动的通道 &activeChannels_以及poll返回的时间
pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);
//++iteration_;
//输出 处于活动状态的channel 到日志中
if (Logger::logLevel() <= Logger::TRACE)
{
printActiveChannels();
}
// TODO sort channel by priority
//当前事件处理状态设为true
eventHandling_ = true;
//循环处理活动通道的事件
for (ChannelList::iterator it = activeChannels_.begin();
it != activeChannels_.end(); ++it)
{
currentActiveChannel_ = *it;
currentActiveChannel_->handleEvent(pollReturnTime_);
}
//把当前的活动通道设为 NULL
currentActiveChannel_ = NULL;
//当前事件处理状态设为false
eventHandling_ = false;
//doPendingFunctors();
}
LOG_TRACE << "EventLoop " << this << " stop looping";
looping_ = false;
}
//该函数可以跨线程调用,这也是防止程序
void EventLoop::quit()
{
quit_ = true; //由于是多线程访问这个变量,那么是否需要保护这个变量??,要的。但是quit_是布尔类型,是一种对布尔类型的变量操作是一种原子操作,所以我们不用显式的进行保护了
if (!isInLoopThread())
{
//wakeup();
}
}
// 用于注册或者更新 channel的事件
void EventLoop::updateChannel(Channel* channel)
{
// 断言Channel 是否属于当前的EventLoop对象
assert(channel->ownerLoop() == this);
// 断言EventLoop所属的线程是当前的线程
assertInLoopThread();
// 更新channel的事件
poller_->updateChannel(channel);
}
void EventLoop::removeChannel(Channel* channel)
{
assert(channel->ownerLoop() == this);
assertInLoopThread();
if (eventHandling_)
{
assert(currentActiveChannel_ == channel ||
std::find(activeChannels_.begin(), activeChannels_.end(), channel) == activeChannels_.end());
}
poller_->removeChannel(channel);
}
//如果不是在LoopThread线程中将终止线程
void EventLoop::abortNotInLoopThread()
{
LOG_FATAL << "EventLoop::abortNotInLoopThread - EventLoop " << this
<< " was created in threadId_ = " << threadId_
<< ", current thread id = " << CurrentThread::tid();
}
/*打印处于活动状态的channel 到日志中*/
void EventLoop::printActiveChannels() const
{
for (ChannelList::const_iterator it = activeChannels_.begin();
it != activeChannels_.end(); ++it)
{
const Channel* ch = *it;
LOG_TRACE << "{" << ch->reventsToString() << "} ";
}
}
poller.h
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
//
// This is an internal header file, you should not include this.
#ifndef MUDUO_NET_POLLER_H
#define MUDUO_NET_POLLER_H
#include
#include
#include
#include
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 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;
static Poller* newDefaultPoller(EventLoop* loop);
void assertInLoopThread()
{
ownerLoop_->assertInLoopThread();
}
private:
EventLoop* ownerLoop_; // Poller所属EventLoop
};
}
}
#endif // MUDUO_NET_POLLER_H
poller.cc
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
#include
using namespace muduo;
using namespace muduo::net;
Poller::Poller(EventLoop* loop)
: ownerLoop_(loop)
{
}
Poller::~Poller()
{
}
pollpoller.h
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
//
// This is an internal header file, you should not include this.
#ifndef MUDUO_NET_POLLER_POLLPOLLER_H
#define MUDUO_NET_POLLER_POLLPOLLER_H
#include
#include
pollpoller.cc
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
#include
#include
#include
#include
#include
#include
using namespace muduo;
using namespace muduo::net;
PollPoller::PollPoller(EventLoop* loop)
: Poller(loop)
{
}
PollPoller::~PollPoller()
{
}
/*
真正的poll 函数,终于到主角了^<>^ ///
**/
Timestamp PollPoller::poll(int timeoutMs, ChannelList* activeChannels)
{
// XXX pollfds_ shouldn't change
int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs);
Timestamp now(Timestamp::now());
//如果有活动事件 , 则填充到activeChannels 中去
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;
}
//填充活动通道
// activeChannels 活动通道
// pollfds_ 已注册的事件集合
/*被关注的通道列表 , 不是活动的通道列表*/
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;
// 从关注列表channels_中找出 已产生事件 的fd---》channel
ChannelMap::const_iterator ch = channels_.find(pfd->fd);
// 断言是否已近到了channels_的尾部
assert(ch != channels_.end());
// 获取活动channel
Channel* channel = ch->second;
// 断言channel的文件描述符是否和pfd 的描述符一致
assert(channel->fd() == pfd->fd);
// 设置channel的事件
channel->set_revents(pfd->revents);
// pfd->revents = 0;
// 把活动channel 加入activeChannel容器
activeChannels->push_back(channel);
}
}
}
/*
更行channel通道,
**/
void PollPoller::updateChannel(Channel* channel)
{
//断言实在LoopThread 当中
Poller::assertInLoopThread();
LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events();
//如果新的通道,还没有注册事件
if (channel->index() < 0)
{
// index < 0说明是一个新的通道
// a new one, add to pollfds_
//断言是新的通道
assert(channels_.find(channel->fd()) == channels_.end());
//注册事件
struct pollfd pfd;
pfd.fd = channel->fd();
pfd.events = static_cast(channel->events());
pfd.revents = 0;
pollfds_.push_back(pfd);
//channel在pollfds中索引
int idx = static_cast(pollfds_.size())-1;
//更新channel的索引
channel->set_index(idx);
//加入channels_ 的map中
channels_[pfd.fd] = channel;
}
else
{
// update existing one
//断言channel 已存在--》 channels_ ,index >0 < pollfds_.size()
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);
//下面才是真正的更新
pfd.events = static_cast(channel->events());
//revents 貌似不用清零???
pfd.revents = 0;
// 将一个通道暂时更改为不关注事件,但不从Poller中移除该通道
if (channel->isNoneEvent())
{
// ignore this pollfd
// 暂时忽略该文件描述符的事件
// 这里pfd.fd 可以直接设置为-1 , -1是为了排除0描述符的干扰
pfd.fd = -channel->fd()-1; // 这样子设置是为了removeChannel优化
}
}
}
// 把channel 真正的从pollfds 中移除
void PollPoller::removeChannel(Channel* channel)
{
Poller::assertInLoopThread();
LOG_TRACE << "fd = " << channel->fd();
assert(channels_.find(channel->fd()) != channels_.end());
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());
//1-----------》先把channel 从channels_中移除
size_t n = channels_.erase(channel->fd());
assert(n == 1); (void)n;
//2-----------》如果是最后一个,则直接移除
if (implicit_cast(idx) == pollfds_.size()-1)
{
pollfds_.pop_back();
}
else
{
// 2----------》这里移除的算法复杂度是O(1),将待删除元素与最后一个元素交换再pop_back
int channelAtEnd = pollfds_.back().fd;
iter_swap(pollfds_.begin()+idx, pollfds_.end()-1);
//channelAtEnd 是从 pollfds_ 里面拿出来的,所以可能是负数
if (channelAtEnd < 0)
{
channelAtEnd = -channelAtEnd-1;
}
channels_[channelAtEnd]->set_index(idx);
pollfds_.pop_back();
}
}
channel.h
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
//
// This is an internal header file, you should not include this.
#ifndef MUDUO_NET_CHANNEL_H
#define MUDUO_NET_CHANNEL_H
#include
#include
#include
#include
#include
namespace muduo
{
namespace net
{
class EventLoop;
///
/// A selectable I/O channel.
///
/// This class doesn't own the file descriptor.
/// The file descriptor could be a socket,
/// an eventfd, a timerfd, or a signalfd
class Channel : boost::noncopyable //不可拷贝的
{
public:
/*事件回调处理函数*/
typedef boost::function EventCallback;
/*读事件的回调处理*/
typedef boost::function ReadEventCallback;
/*一个EventLoop 包含多个Channel , 一个channel只属于一个EventLoop
Channel(n)-----> EventLoop
*/
Channel(EventLoop* loop, int fd);
//虚构函数没干什么事^V^
~Channel();
void handleEvent(Timestamp receiveTime);
/*回调函数的注册*/
// 读的回调函数
void setReadCallback(const ReadEventCallback& cb)
{ readCallback_ = cb; }
// 写的回调函数
void setWriteCallback(const EventCallback& cb)
{ writeCallback_ = cb; }
// 关闭的回调函数
void setCloseCallback(const EventCallback& cb)
{ closeCallback_ = cb; }
// 出错的回调函数
void setErrorCallback(const EventCallback& cb)
{ errorCallback_ = cb; }
//////////////////////////////////////////////////
/*
这个函数下一节才开始分析^V^ ...
这个函数跟TcpConnection 生命周期是有关系的,为了防止在事件处理的时候
**/
/// Tie this channel to the owner object managed by shared_ptr,
/// prevent the owner object being destroyed in handleEvent.
void tie(const boost::shared_ptr&);
//channel 的描述符
int fd() const { return fd_; }
// channel注册的事件(关注的事件)
int events() const { return events_; }
// poller 实际返回的事件,
void set_revents(int revt) { revents_ = revt; } // used by pollers
//清空channel的事件
// int revents() const { return revents_; }
bool isNoneEvent() const { return events_ == kNoneEvent; }
void enableReading() { events_ |= kReadEvent; update(); }
// void disableReading() { events_ &= ~kReadEvent; update(); }
void enableWriting() { events_ |= kWriteEvent; update(); }
void disableWriting() { events_ &= ~kWriteEvent; update(); }
void disableAll() { events_ = kNoneEvent; update(); }
bool isWriting() const { return events_ & kWriteEvent; }
// for Poller ; 在Poller数组中的索引
int index() { return index_; }
// 设置channel在poller的索引
void set_index(int idx) { index_ = idx; }
// for debug 事件的调试信息
string reventsToString() const;
void doNotLogHup() { logHup_ = false; }
EventLoop* ownerLoop() { return loop_; }
void remove();
private:
void update();
void handleEventWithGuard(Timestamp receiveTime);
//事件常量
//没有事件就是说等于零
static const int kNoneEvent;
static const int kReadEvent;
static const int kWriteEvent;
EventLoop* loop_; // 所属EventLoop
const int fd_; // 文件描述符,但不负责关闭该文件描述符
int events_; // 关注的事件
int revents_; // poll/epoll返回的事件
int index_; // used by Poller.表示在poll的事件数组中的序号
bool logHup_; // for POLLHUP
// 下面两个是负责生存期的控制
boost::weak_ptr tie_;
bool tied_;
bool eventHandling_; // 是否处于处理事件中
ReadEventCallback readCallback_;
EventCallback writeCallback_;
EventCallback closeCallback_;
EventCallback errorCallback_;
};
}
}
#endif // MUDUO_NET_CHANNEL_H
channel.cc
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
#include
#include
#include
#include
#include
using namespace muduo;
using namespace muduo::net;
const int Channel::kNoneEvent = 0; //没有事件
const int Channel::kReadEvent = POLLIN | POLLPRI; //产生量可读事件或者紧急数据
const int Channel::kWriteEvent = POLLOUT;
Channel::Channel(EventLoop* loop, int fd__)
: loop_(loop),
fd_(fd__),
events_(0),
revents_(0),
index_(-1), //没加入poller是,channel的索引为 -1
logHup_(true),
tied_(false),
eventHandling_(false) //channel的事件处理状态初始化为 false
{
}
Channel::~Channel()
{
assert(!eventHandling_);
}
void Channel::tie(const boost::shared_ptr& obj)
{
tie_ = obj;
tied_ = true;
}
//更新channel的事件
void Channel::update()
{
loop_->updateChannel(this);
}
// 调用这个函数之前确保调用disableAll
// void disableAll() { events_ = kNoneEvent; update()-->assert(isNoneEvent()); }
void Channel::remove()
{
assert(isNoneEvent());
loop_->removeChannel(this);
}
/**
当时到达时,调用事件处理函数handleEvent进行处理
*/
void Channel::handleEvent(Timestamp receiveTime)
{
boost::shared_ptr guard;
if (tied_)
{
guard = tie_.lock();
if (guard)
{
handleEventWithGuard(receiveTime);
}
}
else
{
handleEventWithGuard(receiveTime);
}
}
/**
事件处理
**/
void Channel::handleEventWithGuard(Timestamp receiveTime)
{//把channel的事件处理状态设为 true
eventHandling_ = true;
//如果poller返回的channel 事件是pollhup挂断(写时才会产生),并且不是可读的
if ((revents_ & POLLHUP) && !(revents_ & POLLIN))
{
// 如果挂断了
if (logHup_)
{
LOG_WARN << "Channel::handle_event() POLLHUP";
}
//如果挂断了,就返回closeCallback
if (closeCallback_) closeCallback_();
}
//文件描述符不合法或者文件描述符没有打开
if (revents_ & POLLNVAL)
{
LOG_WARN << "Channel::handle_event() POLLNVAL";
}
if (revents_ & (POLLERR | POLLNVAL))
{
if (errorCallback_) errorCallback_();
}
//可读事件 ,
//POLLRDHUP :stream socket peer closed connection ,or shutdown writing half of connection
//POLLPRI : there is urgent data to read
if (revents_ & (POLLIN | POLLPRI | POLLRDHUP))
{
if (readCallback_) readCallback_(receiveTime);
}
//可写事件
if (revents_ & POLLOUT)
{
if (writeCallback_) writeCallback_();
}
//事件处理完后,把事件处理状态恢复为false状态
eventHandling_ = false;
}
string Channel::reventsToString() const
{
std::ostringstream oss;
oss << fd_ << ": ";
if (revents_ & POLLIN)
oss << "IN ";
if (revents_ & POLLPRI)
oss << "PRI ";
if (revents_ & POLLOUT)
oss << "OUT ";
if (revents_ & POLLHUP)
oss << "HUP ";
if (revents_ & POLLRDHUP)
oss << "RDHUP ";
if (revents_ & POLLERR)
oss << "ERR ";
if (revents_ & POLLNVAL)
oss << "NVAL ";
return oss.str().c_str();
}