26muduo_net库源码分析(二)
来源:互联网 发布:医生收入 知乎 编辑:程序博客网 时间:2024/06/12 21:01
1.类图
2.Channel
(1)Channel是selectable IO channel,负责注册与响应IO事件,它不拥有filedescriptor。
(2)Channel是Acceptor、Connector、EventLoop、TimerQueue、TcpConnection的成员,生命期由后者控制。
3.时序图
4.代码
EvevtLoop.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 <vector>#include <boost/noncopyable.hpp>#include <boost/scoped_ptr.hpp>#include <muduo/base/CurrentThread.h>#include <muduo/base/Thread.h>#include <muduo/base/Timestamp.h>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中移除通道 void assertInLoopThread() { if (!isInLoopThread()) { abortNotInLoopThread(); } } bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); } static EventLoop* getEventLoopOfCurrentThread(); private: void abortNotInLoopThread(); void printActiveChannels() const; // DEBUG typedef std::vector<Channel*> ChannelList; bool looping_; /* atomic */ bool quit_; /* atomic */ bool eventHandling_; /* atomic */ const pid_t threadId_;// 当前对象所属线程ID Timestamp pollReturnTime_; boost::scoped_ptr<Poller> poller_; ChannelList activeChannels_;// Poller返回的活动通道 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 <muduo/net/EventLoop.h>#include <muduo/base/Logging.h>#include <muduo/net/Channel.h>#include <muduo/net/Poller.h>//#include <poll.h>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_; } else { t_loopInThisThread = this; }}EventLoop::~EventLoop(){ t_loopInThisThread = NULL;}// 事件循环,该函数不能跨线程调用// 只能在创建该对象的线程中调用void EventLoop::loop(){ assert(!looping_); // 断言当前处于创建该对象的线程中 assertInLoopThread(); looping_ = true; LOG_TRACE << "EventLoop " << this << " start looping"; //::poll(NULL, 0, 5*1000); while (!quit_) { activeChannels_.clear(); pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_); //++iteration_; if (Logger::logLevel() <= Logger::TRACE) { printActiveChannels(); } // TODO sort channel by priority eventHandling_ = true; for (ChannelList::iterator it = activeChannels_.begin(); it != activeChannels_.end(); ++it) { currentActiveChannel_ = *it; currentActiveChannel_->handleEvent(pollReturnTime_); } currentActiveChannel_ = NULL; eventHandling_ = false; //doPendingFunctors(); } LOG_TRACE << "EventLoop " << this << " stop looping"; looping_ = false;}void EventLoop::quit(){ quit_ = true; if (!isInLoopThread()) { //wakeup(); }}void EventLoop::updateChannel(Channel* channel){ assert(channel->ownerLoop() == this); assertInLoopThread(); 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);}void EventLoop::abortNotInLoopThread(){ LOG_FATAL << "EventLoop::abortNotInLoopThread - EventLoop " << this << " was created in threadId_ = " << threadId_ << ", current thread id = " << CurrentThread::tid();}void EventLoop::printActiveChannels() const{ for (ChannelList::const_iterator it = activeChannels_.begin(); it != activeChannels_.end(); ++it) { const Channel* ch = *it; LOG_TRACE << "{" << ch->reventsToString() << "} "; }}
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 <boost/function.hpp>#include <boost/noncopyable.hpp>#include <boost/shared_ptr.hpp>#include <boost/weak_ptr.hpp>#include <muduo/base/Timestamp.h>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 signalfdclass Channel : boost::noncopyable{ public: typedef boost::function<void()> EventCallback; typedef boost::function<void(Timestamp)> ReadEventCallback; Channel(EventLoop* loop, int fd); ~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; } /// 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<void>&); int fd() const { return 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; } 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 int index() { return index_; } 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<void> 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 <muduo/base/Logging.h>#include <muduo/net/Channel.h>#include <muduo/net/EventLoop.h>#include <sstream>#include <poll.h>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), logHup_(true), tied_(false), eventHandling_(false){}Channel::~Channel(){ assert(!eventHandling_);}void Channel::tie(const boost::shared_ptr<void>& obj){ tie_ = obj; tied_ = true;}void Channel::update(){ loop_->updateChannel(this);}// 调用这个函数之前确保调用disableAllvoid Channel::remove(){ assert(isNoneEvent()); loop_->removeChannel(this);}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){ eventHandling_ = true; if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) { if (logHup_) { LOG_WARN << "Channel::handle_event() POLLHUP"; } if (closeCallback_) closeCallback_(); } if (revents_ & POLLNVAL) { LOG_WARN << "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;}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();}
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 <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* 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 <muduo/net/Poller.h>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 <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(); virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels); virtual void updateChannel(Channel* channel); virtual void removeChannel(Channel* channel); private: void fillActiveChannels(int numEvents, ChannelList* activeChannels) const; typedef std::vector<struct pollfd> PollFdList; typedef std::map<int, Channel*> ChannelMap;// key是文件描述符,value是Channel* PollFdList pollfds_; ChannelMap channels_;};}}#endif // MUDUO_NET_POLLER_POLLPOLLER_H
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 <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){ // XXX pollfds_ shouldn't change 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(); 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<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(); }}
阅读全文
1 0
- 26muduo_net库源码分析(二)
- muduo_net库源码分析
- muduo_net库源码分析(26-1
- EpollPoller --- muduo_net库源码分析(27)
- 25muduo_net库源码分析(一)
- 27muduo_net库源码分析(三)
- 28muduo_net库源码分析(四)
- 29muduo_net库源码分析(五)
- 30muduo_net库源码分析(六)
- 31muduo_net库源码分析(七)
- 32muduo_net库源码分析(八)
- 33muduo_net库源码分析(九)
- 34muduo_net库源码分析(十)
- muduo_net库源码分析(25)
- muduo_net库源码分析(25)
- 高并发服务器架构笔记(4)——muduo_net 源码分析
- 11muduo_base库源码分析(二)
- EventBus源码分析(二):编译库源码解析
- CentOS 6.5安装Nginx (一)
- centos 核心与核心模块——查看核心模块信息
- 文本不换行,超出显示省略号
- 【23种设计模式】创建型模式 > 原型模式
- web项目
- 26muduo_net库源码分析(二)
- ABAP Objects Design Patterns – Model View Controller (MVC) Part 1
- prim算法
- 去除二值图像的杂散点
- 利用cron监视后台进程状态(二)
- 算法题目——python基础巩固练习一 斐波那契数列
- Scala保留字
- 容器适配器
- Android之Kotlin实现补间动画-(TweenAnimaion)