// excerpts from 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 "Poller.h" #include "Channel.h" #include "logging/Logging.h" #include #include using namespace muduo; Poller::Poller(EventLoop* loop) : ownerLoop_(loop) { } Poller::~Poller() { } Timestamp Poller::poll(int timeoutMs, ChannelList* activeChannels) { // XXX pollfds_ shouldn't change int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); Timestamp now(Timestamp::now()); if (numEvents > 0) { LOG_TRACE << numEvents << " events happended"; fillActiveChannels(numEvents, activeChannels); } else if (numEvents == 0) { LOG_TRACE << " nothing happended"; } else { LOG_SYSERR << "Poller::poll()"; } return now; } void Poller::fillActiveChannels(int numEvents, ChannelList* activeChannels) const { for (PollFdList::const_iterator pfd = pollfds_.begin(); pfd != pollfds_.end() && numEvents > 0; ++pfd) { if (pfd->revents > 0) { --numEvents; ChannelMap::const_iterator ch = channels_.find(pfd->fd); assert(ch != channels_.end()); Channel* channel = ch->second; assert(channel->fd() == pfd->fd); channel->set_revents(pfd->revents); // pfd->revents = 0; activeChannels->push_back(channel); } } } void Poller::updateChannel(Channel* channel) { assertInLoopThread(); LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events(); if (channel->index() < 0) { // a new one, add to pollfds_ assert(channels_.find(channel->fd()) == channels_.end()); struct pollfd pfd; pfd.fd = channel->fd(); pfd.events = static_cast(channel->events()); pfd.revents = 0; pollfds_.push_back(pfd); int idx = static_cast(pollfds_.size())-1; channel->set_index(idx); channels_[pfd.fd] = channel; } else { // update existing one assert(channels_.find(channel->fd()) != channels_.end()); assert(channels_[channel->fd()] == channel); int idx = channel->index(); assert(0 <= idx && idx < static_cast(pollfds_.size())); struct pollfd& pfd = pollfds_[idx]; ! assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1); pfd.events = static_cast(channel->events()); pfd.revents = 0; if (channel->isNoneEvent()) { // ignore this pollfd ! pfd.fd = -channel->fd()-1; } } } +void Poller::removeChannel(Channel* channel) +{ + assertInLoopThread(); + LOG_TRACE << "fd = " << channel->fd(); + assert(channels_.find(channel->fd()) != channels_.end()); + assert(channels_[channel->fd()] == channel); + assert(channel->isNoneEvent()); + int idx = channel->index(); + assert(0 <= idx && idx < static_cast(pollfds_.size())); + const struct pollfd& pfd = pollfds_[idx]; (void)pfd; + assert(pfd.fd == -channel->fd()-1 && pfd.events == channel->events()); + size_t n = channels_.erase(channel->fd()); + assert(n == 1); (void)n; + if (implicit_cast(idx) == pollfds_.size()-1) + { + pollfds_.pop_back(); + } + else + { + int channelAtEnd = pollfds_.back().fd; + iter_swap(pollfds_.begin()+idx, pollfds_.end()-1); + if (channelAtEnd < 0) + { + channelAtEnd = -channelAtEnd-1; + } + channels_[channelAtEnd]->set_index(idx); + pollfds_.pop_back(); + } +} +