看一下muduo实现的epoll

// 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 <assert.h>
#include <errno.h>
#include <poll.h>
#include <sys/epoll.h>
#include <unistd.h>using namespace muduo;
using namespace muduo::net;/*struct epoll_event
{uint32_t events;   //Epoll eventsepoll_data_t data;    //User data variable
} __attribute__ ((__packed__));typedef union epoll_data
{void *ptr;int fd;uint32_t u32;uint64_t u64;
} epoll_data_t;*/// On Linux, the constants of poll(2) and epoll(4)
// are expected to be the same.
static_assert(EPOLLIN == POLLIN,        "epoll uses same flag values as poll");
static_assert(EPOLLPRI == POLLPRI,      "epoll uses same flag values as poll");
static_assert(EPOLLOUT == POLLOUT,      "epoll uses same flag values as poll");
static_assert(EPOLLRDHUP == POLLRDHUP,  "epoll uses same flag values as poll");
static_assert(EPOLLERR == POLLERR,      "epoll uses same flag values as poll");
static_assert(EPOLLHUP == POLLHUP,      "epoll uses same flag values as poll");namespace
{
const int kNew = -1; //新的
const int kAdded = 1; //已经添加了
const int kDeleted = 2;   //之前监听过了,后来移除了监听
}//当flag = EPOLL_CLOEXEC,创建的epfd会设置FD_CLOEXEC
//FD_CLOEXEC表示当程序执行exec函数时本fd将被系统自动关闭,表示不传递给exec创建的新进程
EPollPoller::EPollPoller(EventLoop* loop): Poller(loop),epollfd_(::epoll_create1(EPOLL_CLOEXEC)),      创建epollfd,使用带1的版本events_(kInitEventListSize)                    //vector这样用时初始化kInitEventListSize个大小空间
{if (epollfd_ < 0)                           //在构造函数中判断,<0就abort(){LOG_SYSFATAL << "EPollPoller::EPollPoller";}
}EPollPoller::~EPollPoller()
{::close(epollfd_);
}Timestamp EPollPoller::poll(int timeoutMs, ChannelList* activeChannels)//ChannelList是一个存放channel的vector
{LOG_TRACE << "fd total count " << channels_.size();int numEvents = ::epoll_wait(epollfd_,&*events_.begin(),  //events_已初始化,是存放epoll_event的vectorstatic_cast<int>(events_.size()),    //监控套接字的数目timeoutMs);int savedErrno = errno;Timestamp now(Timestamp::now());if (numEvents > 0){LOG_TRACE << numEvents << " events happened";fillActiveChannels(numEvents, activeChannels);if (implicit_cast<size_t>(numEvents) == events_.size()) //如果返回的事件数目等于当前事件数组大小,就分配2倍空间{events_.resize(events_.size()*2);}}else if (numEvents == 0){LOG_TRACE << "nothing happened";}else{// error happens, log uncommon onesif (savedErrno != EINTR){errno = savedErrno;LOG_SYSERR << "EPollPoller::poll()";}}return now;
}//把返回到的这么多个事件添加到activeChannels
void EPollPoller::fillActiveChannels(int numEvents,ChannelList* activeChannels) const
{assert(implicit_cast<size_t>(numEvents) <= events_.size());for (int i = 0; i < numEvents; ++i)                          //确定它的大小小于events_的大小,因为events_是预留的事件vector{Channel* channel = static_cast<Channel*>(events_[i].data.ptr);
#ifndef NDEBUGint fd = channel->fd();                       //debug时做一下检测ChannelMap::const_iterator it = channels_.find(fd);assert(it != channels_.end());assert(it->second == channel);
#endifchannel->set_revents(events_[i].events);        //把已发生的事件传给channel,写到通道当中activeChannels->push_back(channel);             //并且push_back进activeChannels}
}//这个函数被调用是因为channel->enablereading()被调用,再调用channel->update(),再event_loop->updateChannel(),再->epoll或poll的updateChannel被调用
//
void EPollPoller::updateChannel(Channel* channel)
{Poller::assertInLoopThread();  //在IO线程const int index = channel->index();  //初始状态index是-1LOG_INFO << "fd = " << channel->fd()<< " events = " << channel->events() << " index = " << index;// 当是新的或是之前监听过,后来移除了监听// 两者的区别在于,新的channel 之前没有在epoll 中保存// 而 del 的之前在 channels_ 中保存了,但是没有被放入epoll_ctl中监听if (index == kNew || index == kDeleted)  //index是在poll中是下标,在epoll中是三种状态,上面有三个常量{// a new one, add with EPOLL_CTL_ADDint fd = channel->fd();if (index == kNew){assert(channels_.find(fd) == channels_.end());  //channels_是一个Mapchannels_[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/DELint 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);    //删除事件channel->set_index(kDeleted);  //删除后被设置为kDeleted}else{update(EPOLL_CTL_MOD, channel);   //修改已注册的监听事件}}
}void EPollPoller::removeChannel(Channel* channel)
{Poller::assertInLoopThread();  //判断是否在IO线程int fd = channel->fd();LOG_TRACE << "fd = " << fd;assert(channels_.find(fd) != channels_.end());assert(channels_[fd] == channel);assert(channel->isNoneEvent());int index = channel->index();assert(index == kAdded || index == kDeleted);size_t n = channels_.erase(fd);   //删除(void)n; assert(n == 1);if (index == kAdded){update(EPOLL_CTL_DEL, channel);}channel->set_index(kNew);
}void EPollPoller::update(int operation, Channel* channel)
{printf("-------%s,line.%d-------\n",__FUNCTION__,__LINE__);struct epoll_event event;    //存放数据的结构体memZero(&event, sizeof event);event.events = channel->events();  //注册的事件event.data.ptr = channel;int fd = channel->fd();LOG_INFO << "epoll_ctl op = " << operationToString(operation)<< " fd = " << fd << " event = { " << channel->eventsToString() << " }";if (::epoll_ctl(epollfd_, operation, fd, &event) < 0)//epoll_ctl失败返回-1{if (operation == EPOLL_CTL_DEL){LOG_SYSERR << "epoll_ctl op =" << operationToString(operation) << " fd =" << fd;}else{LOG_SYSFATAL << "epoll_ctl op =" << operationToString(operation) << " fd =" << fd;}}
}const char* EPollPoller::operationToString(int op)
{switch (op){case EPOLL_CTL_ADD:return "ADD";case EPOLL_CTL_DEL:return "DEL";case EPOLL_CTL_MOD:return "MOD";default:assert(false && "ERROR op");return "Unknown Operation";}
}

muduo之EPollPoller相关推荐

  1. muduo源码client/server通信流程

    今天来学习一下muduo源码中client和server间的大致通信流程,以echo服务为例,先看一下echo对面的main函数代码. #include "examples/simple/e ...

  2. muduo网络库学习(一)对io复用的封装Poller,面向对象与基于对象

    高效并发的网络框架大多离不开io多路复用函数,Linux下有三种 select poll epoll 关于三者的区别可以参考 linux网络编程-–几种服务器模型及io多路复用函数 前段时间看Libe ...

  3. 击鼓传花:对比 muduo 与 libevent2 的事件处理效率

    前面我们比较了 muduo 和 libevent2 的吞吐量,得到的结论是 muduo 比 libevent2 快 18%.有人会说,libevent2 并不是为高吞吐的应用场景而设计的,这样的比较不 ...

  4. 基于C++11的muduo网络库

    文章目录 写在前面 项目编译问题 库安装的问题 项目测试代码 关于压力测试 项目概述 muduo网络库的reactor模型 muduo的设计 muduo各个类 辅助类 NonCopyable Time ...

  5. Muduo网络库核心梳理

    Muduo网络库 Muduo网络库本身并不复杂,是一个新手入门C++面向对象网络编程的经典实战项目.但是,新手在刚刚上手读代码的时候,非常容易陷入代码的汪洋大海,迷失方向.本文旨在简要梳理Muduo网 ...

  6. 长文梳理Muduo库核心代码及优秀编程细节剖析

    一.前言: 代码地址: https://github.com/yyg192/Cpp11-Muduo-MultiReactor  Muduo库是陈硕个人开发的Tcp网络编程库,支持Reactor模型.本 ...

  7. muduo网络库学习总结:基本架构及流程分析

    muduo网络库学习:基本架构及流程分析 基本架构 Basic Reactor Mutiple Reactor + ThreadPool muduo库的基本使用 基本结构介绍 EventLoop类 P ...

  8. muduo网络库学习(1)

    muduo网络库学习(1) 文章目录 muduo网络库学习(1) 前言 一.muduo是什么? 二.代码结构 1.base库 2.net库 3.附属库 二.网络库结构 总结 前言 本章节主要介绍mud ...

  9. linux muduo 编译安装,muduo记录

    1.muduo编译安装 编译muduo遇见的报错可以在github上的issue上面查找.一般都能顺利解决,我遇到的就是没有安装boost-dev. centos7系统 执行: sudo yum in ...

最新文章

  1. 如何设计一个牛逼的本地缓存
  2. 在CodeMash 2012的“ Wat”演讲中提到的这些怪异JavaScript行为的解释是什么?
  3. 用apxs来扩增apache的模块
  4. Android爬坑之旅:软键盘挡住输入框问题的终极解决方案
  5. 写底部样式一定要加的属性
  6. Python Django 常用字段类型
  7. excel分两个独立窗口_Excel2010 多个独立窗口,解决单窗口无法显示多个文件的问题...
  8. vv7无法启动显示发动机故障_点火系统故障引起发动机不能启动的排除方法
  9. 【elasticsearch】elasticsearch 熔断器
  10. 代码管理学:正确理解工作,并不是你想的那样容易
  11. mac上键盘说明以及intellij 快捷键的使用
  12. Axure中引入Echarts图表并制作元件库
  13. 看山聊Java:Date 与 LocalDate 或 LocalDateTime 互相转换
  14. java基础----数据类型
  15. 22年全国程序员1月薪资出炉,年收入 40 万以上的人为何那么多?
  16. 威客理论在国际英文期刊发表
  17. Linux 之父自传《just for fun》读书笔记
  18. 候鸟防关联浏览器原理
  19. Twing Hot Link For PSP 公测版正式发布!
  20. GDGBYY出差总结

热门文章

  1. 【Netty】Netty 核心组件 ( Pipeline | ChannelPipeline )
  2. 【Android NDK 开发】Android Studio 使用 CMake 导入静态库 ( CMake 简介 | 构建脚本路径配置 | 引入静态库 | 指定静态库路径 | 链接动态库 )
  3. 【Android应用开发】Android Studio 错误集锦 -- 将所有的 AS 错误集合到本文
  4. clipboard_monitor_in_win7
  5. jar - 操作jar包的工具
  6. BZOJ 1603: [Usaco2008 Oct]打谷机
  7. CCF 201703-3 Markdown
  8. The RAII Programming Idiom
  9. Android中自定义属性(attrs.xml,TypedArray的使用)
  10. 选择“Win32汇编”的三大理由?