EpollPoller --- muduo_net库源码分析(27)
2013-11-07 09:21
274 查看
EpollPoller的头文件
epollpller.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_EPOLLPOLLER_H #define MUDUO_NET_POLLER_EPOLLPOLLER_H #include <muduo/net/Poller.h> #include <map> #include <vector> struct epoll_event; namespace muduo { namespace net { /// /// IO Multiplexing with epoll(4). /// class EPollPoller : public Poller { public: EPollPoller(EventLoop* loop); virtual ~EPollPoller(); // timeoutMs 超时事件 // activeChannels活动通道 virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels); //更新通道 virtual void updateChannel(Channel* channel); //移除通道 virtual void removeChannel(Channel* channel); private: // EventListd的初始值 static const int kInitEventListSize = 16; void fillActiveChannels(int numEvents, ChannelList* activeChannels) const; //更新 void update(int operation, Channel* channel); typedef std::vector<struct epoll_event> EventList; typedef std::map<int, Channel*> ChannelMap; //文件描述符 = epoll_create1(EPOLL_CLOEXEC),用来表示要关注事件的fd的集合的描述符 int epollfd_; // epoll_wait返回的活动的通道channelList EventList events_; //通道map ChannelMap channels_; }; } } #endif // MUDUO_NET_POLLER_EPOLLPOLLER_H
[/code]
EpollPoller的源文件
epollpoller.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/EPollPoller.h> #include <muduo/base/Logging.h> #include <muduo/net/Channel.h> #include <boost/static_assert.hpp> #include <assert.h> #include <errno.h> #include <poll.h> #include <sys/epoll.h> using namespace muduo; using namespace muduo::net; // On Linux, the constants of poll(2) and epoll(4) // are expected to be the same. BOOST_STATIC_ASSERT(EPOLLIN == POLLIN); BOOST_STATIC_ASSERT(EPOLLPRI == POLLPRI); BOOST_STATIC_ASSERT(EPOLLOUT == POLLOUT); BOOST_STATIC_ASSERT(EPOLLRDHUP == POLLRDHUP); BOOST_STATIC_ASSERT(EPOLLERR == POLLERR); BOOST_STATIC_ASSERT(EPOLLHUP == POLLHUP); namespace { const int kNew = -1; //新通道 const int kAdded = 1; //要关注的通道 const int kDeleted = 2; //要删除的通道 } EPollPoller::EPollPoller(EventLoop* loop) : Poller(loop), epollfd_(::epoll_create1(EPOLL_CLOEXEC)), events_(kInitEventListSize) { if (epollfd_ < 0) { LOG_SYSFATAL << "EPollPoller::EPollPoller"; } } EPollPoller::~EPollPoller() { ::close(epollfd_); } // IO 线程 Timestamp EPollPoller::poll(int timeoutMs, ChannelList* activeChannels) { //监听事件的到来 int numEvents = ::epoll_wait(epollfd_, &*events_.begin(), static_cast<int>(events_.size()), timeoutMs); Timestamp now(Timestamp::now()); if (numEvents > 0) { LOG_TRACE << numEvents << " events happended"; /*添加活动通道channel*/ fillActiveChannels(numEvents, activeChannels); //如果活动通道的容器已满,则增加活动通道容器的容量 if (implicit_cast<size_t>(numEvents) == events_.size()) { events_.resize(events_.size()*2); } } else if (numEvents == 0) { LOG_TRACE << " nothing happended"; } else { LOG_SYSERR << "EPollPoller::poll()"; } return now; } /*添加活动通道channel*/ void EPollPoller::fillActiveChannels(int numEvents, ChannelList* activeChannels) const { assert(implicit_cast<size_t>(numEvents) <= events_.size()); for (int i = 0; i < numEvents; ++i) { Channel* channel = static_cast<Channel*>(events_[i].data.ptr); //如果是调试状态,则 #ifndef NDEBUG int fd = channel->fd(); ChannelMap::const_iterator it = channels_.find(fd); assert(it != channels_.end()); assert(it->second == channel); #endif //否则直接跳到这里 // 设置channel的“可用事件” channel->set_revents(events_[i].events); // 加入活动通道容器 activeChannels->push_back(channel); } } //更新某个通道 channel void EPollPoller::updateChannel(Channel* channel) { //断言 在IO线程中 Poller::assertInLoopThread(); LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events(); //channel 的默认值是 -1 , ---->>channel class const int index = channel->index(); // kNew 表示有新的通道要增加,kDeleted表示将已不关注事件的fd重新关注事件,及时重新加到epollfd_中去 if (index == kNew || index == kDeleted) { // a new one, add with EPOLL_CTL_ADD int fd = channel->fd(); if (index == kNew) { //如果是新的channel,那么在channels_里面是找不到的 assert(channels_.find(fd) == channels_.end()); //添加到channels_中 channels_[fd] = channel; } else // index == kDeleted { assert(channels_.find(fd) != channels_.end()); assert(channels_[fd] == channel); } // channel->set_index(kAdded); update(EPOLL_CTL_ADD, channel); } else { // update existing one with EPOLL_CTL_MOD/DEL int fd = channel->fd(); (void)fd; assert(channels_.find(fd) != channels_.end()); assert(channels_[fd] == channel); //断言已经在channels_里面了,并且已在epollfd_中 assert(index == kAdded); //剔除channel的关注事件 //如果channel没有事件关注了,就把他从epollfd_中剔除掉 if (channel->isNoneEvent()) { update(EPOLL_CTL_DEL, channel); //更新index = kDeleted channel->set_index(kDeleted); } else { update(EPOLL_CTL_MOD, channel); } } } // 移除channel void EPollPoller::removeChannel(Channel* channel) { //断言实在IO线程中 Poller::assertInLoopThread(); int fd = channel->fd(); LOG_TRACE << "fd = " << fd; //断言能在channels_里面找到channel assert(channels_.find(fd) != channels_.end()); assert(channels_[fd] == channel); //断言所要移除的channel已经没有事件关注了,但是此时在event_里面可能还有他的记录 assert(channel->isNoneEvent()); int index = channel->index(); //断言 assert(index == kAdded || index == kDeleted); //真正从channels_里面删除掉channel size_t n = channels_.erase(fd); (void)n; assert(n == 1); //从event_中剔除channel if (index == kAdded) { update(EPOLL_CTL_DEL, channel); } // channel现在变成新的channel了 channel->set_index(kNew); } void EPollPoller::update(int operation, Channel* channel) { struct epoll_event event; bzero(&event, sizeof event); event.events = channel->events(); event.data.ptr = channel; int fd = channel->fd(); //更新操作 if (::epoll_ctl(epollfd_, operation, fd, &event) < 0) { //写入日志 if (operation == EPOLL_CTL_DEL) { LOG_SYSERR << "epoll_ctl op=" << operation << " fd=" << fd; } else { LOG_SYSFATAL << "epoll_ctl op=" << operation << " fd=" << fd; } } }
[/code]
测试程序
Reactor_test03.cc#include <muduo/net/Channel.h> #include <muduo/net/EventLoop.h> #include <boost/bind.hpp> #include <stdio.h> #include <sys/timerfd.h> using namespace muduo; using namespace muduo::net; EventLoop* g_loop; int timerfd; void timeout(Timestamp receiveTime) { printf("Timeout!\n"); uint64_t howmany; ::read(timerfd, &howmany, sizeof howmany); g_loop->quit(); } int main(void) { EventLoop loop; g_loop = &loop; timerfd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); Channel channel(&loop, timerfd); channel.setReadCallback(boost::bind(timeout, _1)); channel.enableReading(); struct itimerspec howlong; bzero(&howlong, sizeof howlong); howlong.it_value.tv_sec = 1; ::timerfd_settime(timerfd, 0, &howlong, NULL); loop.loop(); ::close(timerfd); }
[/code]
程序输出
[root@localhost bin]# ./reactor_test03 20131020 02:24:05.657327Z 4009 TRACE EventLoop EventLoop created 0xBFD2AAD4 in thread 4009 - EventLoop.cc:42 20131020 02:24:05.657513Z 4009 TRACE updateChannel fd = 4 events = 3 - EPollPoller.cc:104 20131020 02:24:05.657554Z 4009 TRACE loop EventLoop 0xBFD2AAD4 start looping - EventLoop.cc:68 20131020 02:24:06.658756Z 4009 TRACE poll 1 events happended - EPollPoller.cc:65 20131020 02:24:06.658972Z 4009 TRACE printActiveChannels {4: IN } - EventLoop.cc:139 Timeout! 20131020 02:24:06.659008Z 4009 TRACE loop EventLoop 0xBFD2AAD4 stop looping - EventLoop.cc:93 [root@localhost bin]#
[/code]
相关文章推荐
- muduo_net库源码分析(26-1
- GPIO模拟I2C程序实现.
- div css 实现tabs标签
- 开箱即用!Android四款系统架构工具
- 清华同方台试机Bioss默认密码
- 汇编语言程序设计读书笔记(3)- 程序范例
- 安全软件应该具备的,你具备了吗?
- TCP连接状态详解
- Makefile详解
- 调整VirtualBox的VDI硬盘文件大小
- 多线程与并发服务器设计(23 - 2 )
- muduo_net库源码分析(25)
- LINK : warning LNK4068: /MACHINE not specified; defaulting to IX86
- 关于Oracle EBS R12 表格XLA_TRANSACTION_ENTITIES 的安全策略(VPD)组研究
- ORACLE 等待事件的分类
- 多线程与并发服务器设计(23-1)
- ora_00845
- PHP识别电脑还是手机访问网站
- eclipse3.6默认指向WebContent目录修改为webRoot 设置说明 .
- tomcat6版本虚拟目录详细配置