Class Diagram:
It can be seen that the approximate relationship
Channel is responsible for registering deleted and responding IO events, has the current state of IO, and holds related callback functions
EventLoop has the event loop capability. It continuously reads IO events from the Poller, feeds them back to the Channel, and executes the callback function of the Channel.
Poller holds the map structure of Channel in the form of <int fd, Channel*>, and its derived class will add a set of related file descriptors (used to read related IO events from system calls)
EventLoop.cpp
wakeupChannel_->setReadCallback( boost::bind(&EventLoop::handleRead, this)); // we are always reading the wakeupfd wakeupChannel_->enableReading();
Perform IO event registration in the constructor, wakeupChannel is used for thread wakeup, when other threads want to close the current thread Loop, call the quit function, use wakeupChannel to send data, and block in poller_->poll(kPollTimeMs, &activeChannels_); Go back and continue, exit the while loop
while (!quit_) { activeChannels_.clear(); //Clear active IO channels pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_); //Wait for Poller to send active IO channels ++iteration_; if (Logger::logLevel() <= Logger::TRACE) { printActiveChannels(); //Output channels } // TODO sort channel by priority eventHandling_ = true; //Handle event status for (ChannelList::iterator it = activeChannels_.begin(); // Traverse each IO channel to process related events it != activeChannels_.end(); ++it) { currentActiveChannel_ = *it; currentActiveChannel_->handleEvent(pollReturnTime_); } currentActiveChannel_ = NULL; eventHandling_ = false; doPendingFunctors(); }
void EventLoop::updateChannel(Channel* channel) //Update the status of the file descriptor corresponding to the Channel in the Poller { assert(channel->ownerLoop() == this); assertInLoopThread(); poller_->updateChannel(channel); }
Channel.h和Channel.cpp
EventLoop* loop_; //Holds the event loop pointer const int fd_; //holds the file descriptor ID int events_; //Events of interest int revents_; // it's the received event types of epoll or poll int index_; // used by Poller. EPoller represents the current IO activity status, and Poller represents the subscript position of the Poller file descriptor array where the current IO is located bool logHup_; boost::weak_ptr<void> tie_; bool tied_; bool eventHandling_; bool addedToLoop_; ReadEventCallback readCallback_; //Event callback function EventCallback writeCallback_; EventCallback closeCallback_; EventCallback errorCallback_;
void Channel::handleEvent(Timestamp receiveTime) { boost::shared_ptr<void> guard; if (tied_) { guard = tie_.lock(); if (guard) { handleEventWithGuard(receiveTime); } } else { handleEventWithGuard(receiveTime); } }
void Channel::handleEventWithGuard(Timestamp receiveTime)The above is the process of calling the function of Channel, and the action of the response is executed according to the status code of revents
Poller.h and Poller.cpp
protected: typedef std::map<int, Channel*> ChannelMap; ChannelMap channels_; // fd,Channel 集合
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; virtual bool hasChannel(Channel* channel) const; static Poller* newDefaultPoller(EventLoop* loop);Several functions that derived classes need to implement, EventLoop calls derived class functions through the base class pointer