Channel事件分发
Channel.h
class Channel : noncopyable
{
public:
typedef std::function<void()> EventCallback;
typedef std::function<void(Timestamp)> ReadEventCallback;
Channel(EventLoop* loop, int fd);
~Channel();
//回调的设置
void handleEvent(Timestamp receiveTime);
void setReadCallback(ReadEventCallback cb)
{ readCallback_ = std::move(cb); }
void setWriteCallback(EventCallback cb)
{ writeCallback_ = std::move(cb); }
void setCloseCallback(EventCallback cb)
{ closeCallback_ = std::move(cb); }
void setErrorCallback(EventCallback cb)
{ errorCallback_ = std::move(cb); }
/// Tie this channel to the owner object managed by shared_ptr,
/// prevent the owner object being destroyed in handleEvent.
void tie(const std::shared_ptr<void>&);
int fd() const { return fd_; } //返回channel关注的fd
int events() const { return events_; }
void set_revents(int revt) { revents_ = revt; } // used by pollers
// int revents() const { return revents_; }
bool isNoneEvent() const { return events_ == kNoneEvent; }
//使得channel关注对应的事件,并且通过update()挂在到树上监听
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; }
bool isReading() const { return events_ & kReadEvent; }
// for Poller
int index() { return index_; } //这个index作用是什么 记录在poll中的下标
void set_index(int idx) { index_ = idx; }
// for debug
string reventsToString() const;
string eventsToString() const;
void doNotLogHup() { logHup_ = false; }
EventLoop* ownerLoop() { return loop_; }
void remove();
private:
static string eventsToString(int fd, int ev);
void update();
void handleEventWithGuard(Timestamp receiveTime);
static const int kNoneEvent; //在cc文件中定义
static const int kReadEvent;
static const int kWriteEvent;
EventLoop* loop_; //一个channel对应一个loop,但是一个loop有多个channel
const int fd_; //channel关注的fd
int events_; //用户设置关心的事件
int revents_; // it's the received event types of epoll or poll 当前活动的事件
int index_; // used by Poller.
bool logHup_;
std::weak_ptr<void> tie_;
bool tied_;
bool eventHandling_;
bool addedToLoop_;
ReadEventCallback readCallback_;
EventCallback writeCallback_;
EventCallback closeCallback_;
EventCallback errorCallback_;
};
构造函数
Channel::Channel(EventLoop* loop, int fd__)
: loop_(loop), //该Channel归那个IO线程管理,一个channel对应一个Eventloop,但是一个Eventloop对应多个channel
fd_(fd__), //每个Channel对应一个fd,不负责关闭
events_(0), //关注的事件
revents_(0), //从IOmultiplexing中接收到的事件类型
index_(-1), //在poll IO multiplexing中的序号
logHup_(true),
tied_(false), //是否绑定
eventHandling_(false), //是否处于事件循环中
addedToLoop_(false)
{
}
事件分发
void Channel::handleEvent(Timestamp receiveTime)
{
std::shared_ptr<void> guard;
if (tied_)
{
guard = tie_.lock();
if (guard)
{
handleEventWithGuard(receiveTime);
}
}
else
{
handleEventWithGuard(receiveTime);
}
}
void Channel::handleEventWithGuard(Timestamp receiveTime)
{
eventHandling_ = true;
LOG_TRACE << reventsToString();
if ((revents_ & POLLHUP) && !(revents_ & POLLIN))
{
if (logHup_)
{
LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLHUP";
}
if (closeCallback_) closeCallback_();
}
if (revents_ & POLLNVAL)
{
LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLNVAL";
}
if (revents_ & (POLLERR | POLLNVAL))
{
if (errorCallback_) errorCallback_();
}
if (revents_ & (POLLIN | POLLPRI | POLLRDHUP))
{
if (readCallback_) readCallback_(receiveTime);
}
if (revents_ & POLLOUT)
{
if (writeCallback_) writeCallback_();
}
eventHandling_ = false;
}
当channel对应的fd由事件发生时,会在poll()中被加入到队列中,然后依次调用这些fd对应的事件回调函数
Channel删除和修改fd关注的事件
接下来就是channel关注的fd的事件的修改以及删除
-----channel.cc
void Channel::update()
{
addedToLoop_ = true;
loop_->updateChannel(this);
}
void Channel::remove()
{
assert(isNoneEvent());
addedToLoop_ = false;
loop_->removeChannel(this);
}
-----EventLoop.cc
void EventLoop::updateChannel(Channel* channel)
{
assert(channel->ownerLoop() == this); //判断channel是否被初始化
assertInLoopThread(); //判断是否为IO线程
poller_->updateChannel(channel); //调用poller的updateChannel
}
//从IO multiplexing 中删除channel
void EventLoop::removeChannel(Channel* channel)
{
assert(channel->ownerLoop() == this);
assertInLoopThread();
if (eventHandling_) //在执行channel回调的时候,会进入此处进行断言(要删除的channel不在activeChannels_中
//或 currentActiveChannel_ = 待删除的channel,在回调中currentActiveChannel_ = 回调channel)
{
assert(currentActiveChannel_ == channel ||
std::find(activeChannels_.begin(), activeChannels_.end(), channel) == activeChannels_.end());
}
poller_->removeChannel(channel);
}
-------poller_.cc
const int kNew = -1; //不在epoll被监听,也不在channels_中
const int kAdded = 1; //在epoll被监听
const int kDeleted = 2; //被epoll删除了,但是还存在channels_中
void EPollPoller::updateChannel(Channel* channel)
{
Poller::assertInLoopThread();
const int index = channel->index();
LOG_TRACE << "fd = " << channel->fd()
<< " events = " << channel->events() << " index = " << index;
if (index == kNew || index == kDeleted)
{
// a new one, add with EPOLL_CTL_ADD
int fd = channel->fd();
if (index == kNew)
{
//channels_ 是一个 map<fd, Channel*>
assert(channels_.find(fd) == channels_.end()); //fd 与 channel的对应关系不存在
channels_[fd] = channel; //以fd为key,加入map中,fd在一个进程中是唯一的
}
else // index == kDeleted
{
assert(channels_.find(fd) != channels_.end()); //在channels_还是可以找到fd
assert(channels_[fd] == channel); //map中fd与channel对应关系也存在
}
channel->set_index(kAdded); //更新channel现在活动的事件
update(EPOLL_CTL_ADD, channel); //添加进入epoll_wait监听
}
else //fd正在epoll中监听
{
// 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); //从红黑树上删除对应的fd
channel->set_index(kDeleted); //更新channel现在活动的事件(需要先删除)
}
else
{
update(EPOLL_CTL_MOD, channel);
}
}
}
/* DEL */
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()); //fd不关心任何事件,可以在别处看到删除一个channel都是现把它关心的事件置为空
int index = channel->index();
assert(index == kAdded || index == kDeleted);
size_t n = channels_.erase(fd); //从channels_删除 channel
(void)n;
assert(n == 1);
if (index == kAdded)
{
update(EPOLL_CTL_DEL, channel);
}
channel->set_index(kNew); //更新channel现在关心的事件
}
/* 由updateChannel/removeChannel调用,真正执行epoll_ctl()控制epoll的函数 */
void EPollPoller::update(int operation, Channel* channel)
{
struct epoll_event event;
memZero(&event, sizeof event);
event.events = channel->events(); //这个channel关心的事件
event.data.ptr = channel; //把ptr指向这个channel(用于传递)
int fd = channel->fd(); //获取这个channel对应的fd
LOG_TRACE << "epoll_ctl op = " << operationToString(operation)
<< " fd = " << fd << " event = { " << channel->eventsToString() << " }";
if (::epoll_ctl(epollfd_, operation, fd, &event) < 0) //挂到红黑树上监听事件的发生,或者从红黑树上删除(取决于opt)
{
if (operation == EPOLL_CTL_DEL)
{
LOG_SYSERR << "epoll_ctl op =" << operationToString(operation) << " fd =" << fd;
}
else
{
LOG_SYSFATAL << "epoll_ctl op =" << operationToString(operation) << " fd =" << fd;
}
}
}
loop循环
void EventLoop::loop()
{
assert(!looping_); //判断当前线程是否存在EventLoop
assertInLoopThread(); //判断当前线程的EventLoop(构造函数记录了创建EventLoop的线程id)
//和调用该函数的线程是否为同一个
looping_ = true;
quit_ = false; // FIXME: what if someone calls quit() before loop() ?
LOG_TRACE << "EventLoop " << this << " start looping";
while (!quit_)
{
activeChannels_.clear();
pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);
++iteration_;
if (Logger::logLevel() <= Logger::TRACE)
{
printActiveChannels();
}
// TODO sort channel by priority
eventHandling_ = true;
/*
保证在执行channel的回调时,channel不会被remove()删除
和currentActiveChannel_一起确保
*/
for (Channel* channel : activeChannels_)
{
currentActiveChannel_ = channel;
currentActiveChannel_->handleEvent(pollReturnTime_); //执行每一个事件的回调
}
currentActiveChannel_ = NULL;
eventHandling_ = false;
doPendingFunctors(); //执行在其他线程加入的回调
}
在一次循环,会做以下这些事情
1.从poll()中获取事件发生的channel,并且把它们放入activeChannels_中
2.依次从activeChannels_获取对应的channel,并且调用对应的回调函数
3.之后执行doPendingFunctors(),以进入这个函数时刻为准,把队列里面的函数依次执行,如果在执行这些函数时,又有新的函数添加到队列,那么会触发wakeupChannel_的可读事件(也就是唤醒IO线程)