muduo之EPollPoller
生活随笔
收集整理的這篇文章主要介紹了
muduo之EPollPoller
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
? ? ? ? ?看一下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的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: muduo之TcpServer
- 下一篇: muduo之channel