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