1354280cfSShuo Chen// excerpts from http://code.google.com/p/muduo/
2354280cfSShuo Chen//
3354280cfSShuo Chen// Use of this source code is governed by a BSD-style license
4354280cfSShuo Chen// that can be found in the License file.
5354280cfSShuo Chen//
6354280cfSShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com)
7354280cfSShuo Chen
8354280cfSShuo Chen#include "Poller.h"
9354280cfSShuo Chen
10354280cfSShuo Chen#include "Channel.h"
11354280cfSShuo Chen#include "logging/Logging.h"
12354280cfSShuo Chen
13354280cfSShuo Chen#include <assert.h>
14354280cfSShuo Chen#include <poll.h>
15354280cfSShuo Chen
16354280cfSShuo Chenusing namespace muduo;
17354280cfSShuo Chen
18354280cfSShuo ChenPoller::Poller(EventLoop* loop)
19354280cfSShuo Chen  : ownerLoop_(loop)
20354280cfSShuo Chen{
21354280cfSShuo Chen}
22354280cfSShuo Chen
23354280cfSShuo ChenPoller::~Poller()
24354280cfSShuo Chen{
25354280cfSShuo Chen}
26354280cfSShuo Chen
27354280cfSShuo ChenTimestamp Poller::poll(int timeoutMs, ChannelList* activeChannels)
28354280cfSShuo Chen{
29354280cfSShuo Chen  // XXX pollfds_ shouldn't change
30354280cfSShuo Chen  int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs);
31354280cfSShuo Chen  Timestamp now(Timestamp::now());
32354280cfSShuo Chen  if (numEvents > 0) {
33354280cfSShuo Chen    LOG_TRACE << numEvents << " events happended";
34354280cfSShuo Chen    fillActiveChannels(numEvents, activeChannels);
35354280cfSShuo Chen  } else if (numEvents == 0) {
36354280cfSShuo Chen    LOG_TRACE << " nothing happended";
37354280cfSShuo Chen  } else {
38354280cfSShuo Chen    LOG_SYSERR << "Poller::poll()";
39354280cfSShuo Chen  }
40354280cfSShuo Chen  return now;
41354280cfSShuo Chen}
42354280cfSShuo Chen
43354280cfSShuo Chenvoid Poller::fillActiveChannels(int numEvents,
44354280cfSShuo Chen                                ChannelList* activeChannels) const
45354280cfSShuo Chen{
46354280cfSShuo Chen  for (PollFdList::const_iterator pfd = pollfds_.begin();
47354280cfSShuo Chen      pfd != pollfds_.end() && numEvents > 0; ++pfd)
48354280cfSShuo Chen  {
49354280cfSShuo Chen    if (pfd->revents > 0)
50354280cfSShuo Chen    {
51354280cfSShuo Chen      --numEvents;
52354280cfSShuo Chen      ChannelMap::const_iterator ch = channels_.find(pfd->fd);
53354280cfSShuo Chen      assert(ch != channels_.end());
54354280cfSShuo Chen      Channel* channel = ch->second;
55354280cfSShuo Chen      assert(channel->fd() == pfd->fd);
56354280cfSShuo Chen      channel->set_revents(pfd->revents);
57354280cfSShuo Chen      // pfd->revents = 0;
58354280cfSShuo Chen      activeChannels->push_back(channel);
59354280cfSShuo Chen    }
60354280cfSShuo Chen  }
61354280cfSShuo Chen}
62354280cfSShuo Chen
63354280cfSShuo Chenvoid Poller::updateChannel(Channel* channel)
64354280cfSShuo Chen{
65354280cfSShuo Chen  assertInLoopThread();
66354280cfSShuo Chen  LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events();
67354280cfSShuo Chen  if (channel->index() < 0) {
68354280cfSShuo Chen    // a new one, add to pollfds_
69354280cfSShuo Chen    assert(channels_.find(channel->fd()) == channels_.end());
70354280cfSShuo Chen    struct pollfd pfd;
71354280cfSShuo Chen    pfd.fd = channel->fd();
72354280cfSShuo Chen    pfd.events = static_cast<short>(channel->events());
73354280cfSShuo Chen    pfd.revents = 0;
74354280cfSShuo Chen    pollfds_.push_back(pfd);
75354280cfSShuo Chen    int idx = static_cast<int>(pollfds_.size())-1;
76354280cfSShuo Chen    channel->set_index(idx);
77354280cfSShuo Chen    channels_[pfd.fd] = channel;
78354280cfSShuo Chen  } else {
79354280cfSShuo Chen    // update existing one
80354280cfSShuo Chen    assert(channels_.find(channel->fd()) != channels_.end());
81354280cfSShuo Chen    assert(channels_[channel->fd()] == channel);
82354280cfSShuo Chen    int idx = channel->index();
83354280cfSShuo Chen    assert(0 <= idx && idx < static_cast<int>(pollfds_.size()));
84354280cfSShuo Chen    struct pollfd& pfd = pollfds_[idx];
85354280cfSShuo Chen    assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1);
86354280cfSShuo Chen    pfd.events = static_cast<short>(channel->events());
87354280cfSShuo Chen    pfd.revents = 0;
88354280cfSShuo Chen    if (channel->isNoneEvent()) {
89354280cfSShuo Chen      // ignore this pollfd
90354280cfSShuo Chen      pfd.fd = -channel->fd()-1;
91354280cfSShuo Chen    }
92354280cfSShuo Chen  }
93354280cfSShuo Chen}
94354280cfSShuo Chen
95354280cfSShuo Chenvoid Poller::removeChannel(Channel* channel)
96354280cfSShuo Chen{
97354280cfSShuo Chen  assertInLoopThread();
98354280cfSShuo Chen  LOG_TRACE << "fd = " << channel->fd();
99354280cfSShuo Chen  assert(channels_.find(channel->fd()) != channels_.end());
100354280cfSShuo Chen  assert(channels_[channel->fd()] == channel);
101354280cfSShuo Chen  assert(channel->isNoneEvent());
102354280cfSShuo Chen  int idx = channel->index();
103354280cfSShuo Chen  assert(0 <= idx && idx < static_cast<int>(pollfds_.size()));
104354280cfSShuo Chen  const struct pollfd& pfd = pollfds_[idx]; (void)pfd;
105354280cfSShuo Chen  assert(pfd.fd == -channel->fd()-1 && pfd.events == channel->events());
106354280cfSShuo Chen  size_t n = channels_.erase(channel->fd());
107354280cfSShuo Chen  assert(n == 1); (void)n;
108354280cfSShuo Chen  if (implicit_cast<size_t>(idx) == pollfds_.size()-1) {
109354280cfSShuo Chen    pollfds_.pop_back();
110354280cfSShuo Chen  } else {
111354280cfSShuo Chen    int channelAtEnd = pollfds_.back().fd;
112354280cfSShuo Chen    iter_swap(pollfds_.begin()+idx, pollfds_.end()-1);
113354280cfSShuo Chen    if (channelAtEnd < 0) {
114354280cfSShuo Chen      channelAtEnd = -channelAtEnd-1;
115354280cfSShuo Chen    }
116354280cfSShuo Chen    channels_[channelAtEnd]->set_index(idx);
117354280cfSShuo Chen    pollfds_.pop_back();
118354280cfSShuo Chen  }
119354280cfSShuo Chen}
120354280cfSShuo Chen
121