12a18e699SShuo Chen// excerpts from http://code.google.com/p/muduo/
22a18e699SShuo Chen//
32a18e699SShuo Chen// Use of this source code is governed by a BSD-style license
42a18e699SShuo Chen// that can be found in the License file.
52a18e699SShuo Chen//
62a18e699SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com)
72a18e699SShuo Chen
82a18e699SShuo Chen#include "Poller.h"
92a18e699SShuo Chen
102a18e699SShuo Chen#include "Channel.h"
112a18e699SShuo Chen#include "logging/Logging.h"
122a18e699SShuo Chen
132a18e699SShuo Chen#include <assert.h>
142a18e699SShuo Chen#include <poll.h>
152a18e699SShuo Chen
162a18e699SShuo Chenusing namespace muduo;
172a18e699SShuo Chen
182a18e699SShuo ChenPoller::Poller(EventLoop* loop)
192a18e699SShuo Chen  : ownerLoop_(loop)
202a18e699SShuo Chen{
212a18e699SShuo Chen}
222a18e699SShuo Chen
232a18e699SShuo ChenPoller::~Poller()
242a18e699SShuo Chen{
252a18e699SShuo Chen}
262a18e699SShuo Chen
272a18e699SShuo ChenTimestamp Poller::poll(int timeoutMs, ChannelList* activeChannels)
282a18e699SShuo Chen{
292a18e699SShuo Chen  // XXX pollfds_ shouldn't change
302a18e699SShuo Chen  int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs);
312a18e699SShuo Chen  Timestamp now(Timestamp::now());
32b4a5ce52SShuo Chen  if (numEvents > 0) {
332a18e699SShuo Chen    LOG_TRACE << numEvents << " events happended";
342a18e699SShuo Chen    fillActiveChannels(numEvents, activeChannels);
35b4a5ce52SShuo Chen  } else if (numEvents == 0) {
362a18e699SShuo Chen    LOG_TRACE << " nothing happended";
37b4a5ce52SShuo Chen  } else {
382a18e699SShuo Chen    LOG_SYSERR << "Poller::poll()";
392a18e699SShuo Chen  }
402a18e699SShuo Chen  return now;
412a18e699SShuo Chen}
422a18e699SShuo Chen
432a18e699SShuo Chenvoid Poller::fillActiveChannels(int numEvents,
442a18e699SShuo Chen                                ChannelList* activeChannels) const
452a18e699SShuo Chen{
462a18e699SShuo Chen  for (PollFdList::const_iterator pfd = pollfds_.begin();
472a18e699SShuo Chen      pfd != pollfds_.end() && numEvents > 0; ++pfd)
482a18e699SShuo Chen  {
492a18e699SShuo Chen    if (pfd->revents > 0)
502a18e699SShuo Chen    {
512a18e699SShuo Chen      --numEvents;
522a18e699SShuo Chen      ChannelMap::const_iterator ch = channels_.find(pfd->fd);
532a18e699SShuo Chen      assert(ch != channels_.end());
542a18e699SShuo Chen      Channel* channel = ch->second;
552a18e699SShuo Chen      assert(channel->fd() == pfd->fd);
562a18e699SShuo Chen      channel->set_revents(pfd->revents);
572a18e699SShuo Chen      // pfd->revents = 0;
582a18e699SShuo Chen      activeChannels->push_back(channel);
592a18e699SShuo Chen    }
602a18e699SShuo Chen  }
612a18e699SShuo Chen}
622a18e699SShuo Chen
632a18e699SShuo Chenvoid Poller::updateChannel(Channel* channel)
642a18e699SShuo Chen{
652a18e699SShuo Chen  assertInLoopThread();
662a18e699SShuo Chen  LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events();
67b4a5ce52SShuo Chen  if (channel->index() < 0) {
682a18e699SShuo Chen    // a new one, add to pollfds_
692a18e699SShuo Chen    assert(channels_.find(channel->fd()) == channels_.end());
702a18e699SShuo Chen    struct pollfd pfd;
712a18e699SShuo Chen    pfd.fd = channel->fd();
722a18e699SShuo Chen    pfd.events = static_cast<short>(channel->events());
732a18e699SShuo Chen    pfd.revents = 0;
742a18e699SShuo Chen    pollfds_.push_back(pfd);
752a18e699SShuo Chen    int idx = static_cast<int>(pollfds_.size())-1;
762a18e699SShuo Chen    channel->set_index(idx);
772a18e699SShuo Chen    channels_[pfd.fd] = channel;
78b4a5ce52SShuo Chen  } else {
792a18e699SShuo Chen    // update existing one
802a18e699SShuo Chen    assert(channels_.find(channel->fd()) != channels_.end());
812a18e699SShuo Chen    assert(channels_[channel->fd()] == channel);
822a18e699SShuo Chen    int idx = channel->index();
832a18e699SShuo Chen    assert(0 <= idx && idx < static_cast<int>(pollfds_.size()));
842a18e699SShuo Chen    struct pollfd& pfd = pollfds_[idx];
852a18e699SShuo Chen    assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1);
862a18e699SShuo Chen    pfd.events = static_cast<short>(channel->events());
872a18e699SShuo Chen    pfd.revents = 0;
88b4a5ce52SShuo Chen    if (channel->isNoneEvent()) {
892a18e699SShuo Chen      // ignore this pollfd
902a18e699SShuo Chen      pfd.fd = -channel->fd()-1;
912a18e699SShuo Chen    }
922a18e699SShuo Chen  }
932a18e699SShuo Chen}
942a18e699SShuo Chen
952a18e699SShuo Chenvoid Poller::removeChannel(Channel* channel)
962a18e699SShuo Chen{
972a18e699SShuo Chen  assertInLoopThread();
982a18e699SShuo Chen  LOG_TRACE << "fd = " << channel->fd();
992a18e699SShuo Chen  assert(channels_.find(channel->fd()) != channels_.end());
1002a18e699SShuo Chen  assert(channels_[channel->fd()] == channel);
1012a18e699SShuo Chen  assert(channel->isNoneEvent());
1022a18e699SShuo Chen  int idx = channel->index();
1032a18e699SShuo Chen  assert(0 <= idx && idx < static_cast<int>(pollfds_.size()));
1042a18e699SShuo Chen  const struct pollfd& pfd = pollfds_[idx]; (void)pfd;
1052a18e699SShuo Chen  assert(pfd.fd == -channel->fd()-1 && pfd.events == channel->events());
1062a18e699SShuo Chen  size_t n = channels_.erase(channel->fd());
1072a18e699SShuo Chen  assert(n == 1); (void)n;
108b4a5ce52SShuo Chen  if (implicit_cast<size_t>(idx) == pollfds_.size()-1) {
1092a18e699SShuo Chen    pollfds_.pop_back();
110b4a5ce52SShuo Chen  } else {
1112a18e699SShuo Chen    int channelAtEnd = pollfds_.back().fd;
1122a18e699SShuo Chen    iter_swap(pollfds_.begin()+idx, pollfds_.end()-1);
113b4a5ce52SShuo Chen    if (channelAtEnd < 0) {
1142a18e699SShuo Chen      channelAtEnd = -channelAtEnd-1;
1152a18e699SShuo Chen    }
1162a18e699SShuo Chen    channels_[channelAtEnd]->set_index(idx);
1172a18e699SShuo Chen    pollfds_.pop_back();
1182a18e699SShuo Chen  }
1192a18e699SShuo Chen}
1202a18e699SShuo Chen
121