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