1// excerpts from http://code.google.com/p/muduo/ 2// 3// Use of this source code is governed by a BSD-style license 4// that can be found in the License file. 5// 6// Author: Shuo Chen (chenshuo at chenshuo dot com) 7 8#include "EPoller.h" 9 10#include "Channel.h" 11#include "logging/Logging.h" 12 13 14#include <boost/static_assert.hpp> 15 16#include <assert.h> 17#include <errno.h> 18#include <poll.h> 19#include <sys/epoll.h> 20 21using namespace muduo; 22 23// On Linux, the constants of poll(2) and epoll(4) 24// are expected to be the same. 25BOOST_STATIC_ASSERT(EPOLLIN == POLLIN); 26BOOST_STATIC_ASSERT(EPOLLPRI == POLLPRI); 27BOOST_STATIC_ASSERT(EPOLLOUT == POLLOUT); 28BOOST_STATIC_ASSERT(EPOLLRDHUP == POLLRDHUP); 29BOOST_STATIC_ASSERT(EPOLLERR == POLLERR); 30BOOST_STATIC_ASSERT(EPOLLHUP == POLLHUP); 31 32namespace 33{ 34const int kNew = -1; 35const int kAdded = 1; 36const int kDeleted = 2; 37} 38 39EPoller::EPoller(EventLoop* loop) 40 : ownerLoop_(loop), 41 epollfd_(::epoll_create1(EPOLL_CLOEXEC)), 42 events_(kInitEventListSize) 43{ 44 if (epollfd_ < 0) 45 { 46 LOG_SYSFATAL << "EPoller::EPoller"; 47 } 48} 49 50EPoller::~EPoller() 51{ 52 ::close(epollfd_); 53} 54 55Timestamp EPoller::poll(int timeoutMs, ChannelList* activeChannels) 56{ 57 int numEvents = ::epoll_wait(epollfd_, 58 &*events_.begin(), 59 static_cast<int>(events_.size()), 60 timeoutMs); 61 Timestamp now(Timestamp::now()); 62 if (numEvents > 0) 63 { 64 LOG_TRACE << numEvents << " events happended"; 65 fillActiveChannels(numEvents, activeChannels); 66 if (implicit_cast<size_t>(numEvents) == events_.size()) 67 { 68 events_.resize(events_.size()*2); 69 } 70 } 71 else if (numEvents == 0) 72 { 73 LOG_TRACE << " nothing happended"; 74 } 75 else 76 { 77 LOG_SYSERR << "EPoller::poll()"; 78 } 79 return now; 80} 81 82void EPoller::fillActiveChannels(int numEvents, 83 ChannelList* activeChannels) const 84{ 85 assert(implicit_cast<size_t>(numEvents) <= events_.size()); 86 for (int i = 0; i < numEvents; ++i) 87 { 88 Channel* channel = static_cast<Channel*>(events_[i].data.ptr); 89#ifndef NDEBUG 90 int fd = channel->fd(); 91 ChannelMap::const_iterator it = channels_.find(fd); 92 assert(it != channels_.end()); 93 assert(it->second == channel); 94#endif 95 channel->set_revents(events_[i].events); 96 activeChannels->push_back(channel); 97 } 98} 99 100void EPoller::updateChannel(Channel* channel) 101{ 102 assertInLoopThread(); 103 LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events(); 104 const int index = channel->index(); 105 if (index == kNew || index == kDeleted) 106 { 107 // a new one, add with EPOLL_CTL_ADD 108 int fd = channel->fd(); 109 if (index == kNew) 110 { 111 assert(channels_.find(fd) == channels_.end()); 112 channels_[fd] = channel; 113 } 114 else // index == kDeleted 115 { 116 assert(channels_.find(fd) != channels_.end()); 117 assert(channels_[fd] == channel); 118 } 119 channel->set_index(kAdded); 120 update(EPOLL_CTL_ADD, channel); 121 } 122 else 123 { 124 // update existing one with EPOLL_CTL_MOD/DEL 125 int fd = channel->fd(); 126 (void)fd; 127 assert(channels_.find(fd) != channels_.end()); 128 assert(channels_[fd] == channel); 129 assert(index == kAdded); 130 if (channel->isNoneEvent()) 131 { 132 update(EPOLL_CTL_DEL, channel); 133 channel->set_index(kDeleted); 134 } 135 else 136 { 137 update(EPOLL_CTL_MOD, channel); 138 } 139 } 140} 141 142void EPoller::removeChannel(Channel* channel) 143{ 144 assertInLoopThread(); 145 int fd = channel->fd(); 146 LOG_TRACE << "fd = " << fd; 147 assert(channels_.find(fd) != channels_.end()); 148 assert(channels_[fd] == channel); 149 assert(channel->isNoneEvent()); 150 int index = channel->index(); 151 assert(index == kAdded || index == kDeleted); 152 size_t n = channels_.erase(fd); 153 (void)n; 154 assert(n == 1); 155 156 if (index == kAdded) 157 { 158 update(EPOLL_CTL_DEL, channel); 159 } 160 channel->set_index(kNew); 161} 162 163void EPoller::update(int operation, Channel* channel) 164{ 165 struct epoll_event event; 166 bzero(&event, sizeof event); 167 event.events = channel->events(); 168 event.data.ptr = channel; 169 int fd = channel->fd(); 170 if (::epoll_ctl(epollfd_, operation, fd, &event) < 0) 171 { 172 if (operation == EPOLL_CTL_DEL) 173 { 174 LOG_SYSERR << "epoll_ctl op=" << operation << " fd=" << fd; 175 } 176 else 177 { 178 LOG_SYSFATAL << "epoll_ctl op=" << operation << " fd=" << fd; 179 } 180 } 181} 182 183