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 
16 using namespace muduo;
17 
18 Poller::Poller(EventLoop* loop)
19   : ownerLoop_(loop)
20 {
21 }
22 
23 Poller::~Poller()
24 {
25 }
26 
27 Timestamp 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 
43 void 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 
63 void 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 
95+void 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