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 "Poller.h" 9 10#include "Channel.h" 11#include "logging/Logging.h" 12 13#include <assert.h> 14#include <poll.h> 15 16using namespace muduo; 17 18Poller::Poller(EventLoop* loop) 19 : ownerLoop_(loop) 20{ 21} 22 23Poller::~Poller() 24{ 25} 26 27Timestamp Poller::poll(int timeoutMs, ChannelList* activeChannels) 28{ 29 // XXX pollfds_ shouldn't change 30 int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); 31 Timestamp now(Timestamp::now()); 32 if (numEvents > 0) { 33 LOG_TRACE << numEvents << " events happended"; 34 fillActiveChannels(numEvents, activeChannels); 35 } else if (numEvents == 0) { 36 LOG_TRACE << " nothing happended"; 37 } else { 38 LOG_SYSERR << "Poller::poll()"; 39 } 40 return now; 41} 42 43void Poller::fillActiveChannels(int numEvents, 44 ChannelList* activeChannels) const 45{ 46 for (PollFdList::const_iterator pfd = pollfds_.begin(); 47 pfd != pollfds_.end() && numEvents > 0; ++pfd) 48 { 49 if (pfd->revents > 0) 50 { 51 --numEvents; 52 ChannelMap::const_iterator ch = channels_.find(pfd->fd); 53 assert(ch != channels_.end()); 54 Channel* channel = ch->second; 55 assert(channel->fd() == pfd->fd); 56 channel->set_revents(pfd->revents); 57 // pfd->revents = 0; 58 activeChannels->push_back(channel); 59 } 60 } 61} 62 63void Poller::updateChannel(Channel* channel) 64{ 65 assertInLoopThread(); 66 LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events(); 67 if (channel->index() < 0) { 68 // a new one, add to pollfds_ 69 assert(channels_.find(channel->fd()) == channels_.end()); 70 struct pollfd pfd; 71 pfd.fd = channel->fd(); 72 pfd.events = static_cast<short>(channel->events()); 73 pfd.revents = 0; 74 pollfds_.push_back(pfd); 75 int idx = static_cast<int>(pollfds_.size())-1; 76 channel->set_index(idx); 77 channels_[pfd.fd] = channel; 78 } else { 79 // update existing one 80 assert(channels_.find(channel->fd()) != channels_.end()); 81 assert(channels_[channel->fd()] == channel); 82 int idx = channel->index(); 83 assert(0 <= idx && idx < static_cast<int>(pollfds_.size())); 84 struct pollfd& pfd = pollfds_[idx]; 85 assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1); 86 pfd.events = static_cast<short>(channel->events()); 87 pfd.revents = 0; 88 if (channel->isNoneEvent()) { 89 // ignore this pollfd 90 pfd.fd = -channel->fd()-1; 91 } 92 } 93} 94 95void Poller::removeChannel(Channel* channel) 96{ 97 assertInLoopThread(); 98 LOG_TRACE << "fd = " << channel->fd(); 99 assert(channels_.find(channel->fd()) != channels_.end()); 100 assert(channels_[channel->fd()] == channel); 101 assert(channel->isNoneEvent()); 102 int idx = channel->index(); 103 assert(0 <= idx && idx < static_cast<int>(pollfds_.size())); 104 const struct pollfd& pfd = pollfds_[idx]; (void)pfd; 105 assert(pfd.fd == -channel->fd()-1 && pfd.events == channel->events()); 106 size_t n = channels_.erase(channel->fd()); 107 assert(n == 1); (void)n; 108 if (implicit_cast<size_t>(idx) == pollfds_.size()-1) { 109 pollfds_.pop_back(); 110 } else { 111 int channelAtEnd = pollfds_.back().fd; 112 iter_swap(pollfds_.begin()+idx, pollfds_.end()-1); 113 if (channelAtEnd < 0) { 114 channelAtEnd = -channelAtEnd-1; 115 } 116 channels_[channelAtEnd]->set_index(idx); 117 pollfds_.pop_back(); 118 } 119} 120 121