1048f6023SShuo Chen // excerpts from http://code.google.com/p/muduo/
2048f6023SShuo Chen //
3048f6023SShuo Chen // Use of this source code is governed by a BSD-style license
4048f6023SShuo Chen // that can be found in the License file.
5048f6023SShuo Chen //
6048f6023SShuo Chen // Author: Shuo Chen (chenshuo at chenshuo dot com)
7048f6023SShuo Chen 
8048f6023SShuo Chen #include "Poller.h"
9048f6023SShuo Chen 
10048f6023SShuo Chen #include "Channel.h"
11048f6023SShuo Chen #include "logging/Logging.h"
12048f6023SShuo Chen 
13048f6023SShuo Chen #include <assert.h>
14048f6023SShuo Chen #include <poll.h>
15048f6023SShuo Chen 
16048f6023SShuo Chen using namespace muduo;
17048f6023SShuo Chen 
18048f6023SShuo Chen Poller::Poller(EventLoop* loop)
19048f6023SShuo Chen   : ownerLoop_(loop)
20048f6023SShuo Chen {
21048f6023SShuo Chen }
22048f6023SShuo Chen 
23048f6023SShuo Chen Poller::~Poller()
24048f6023SShuo Chen {
25048f6023SShuo Chen }
26048f6023SShuo Chen 
27048f6023SShuo Chen Timestamp Poller::poll(int timeoutMs, ChannelList* activeChannels)
28048f6023SShuo Chen {
29048f6023SShuo Chen   // XXX pollfds_ shouldn't change
30048f6023SShuo Chen   int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs);
31048f6023SShuo Chen   Timestamp now(Timestamp::now());
32b4a5ce52SShuo Chen   if (numEvents > 0) {
33048f6023SShuo Chen     LOG_TRACE << numEvents << " events happended";
34048f6023SShuo Chen     fillActiveChannels(numEvents, activeChannels);
35b4a5ce52SShuo Chen   } else if (numEvents == 0) {
36048f6023SShuo Chen     LOG_TRACE << " nothing happended";
37b4a5ce52SShuo Chen   } else {
38048f6023SShuo Chen     LOG_SYSERR << "Poller::poll()";
39048f6023SShuo Chen   }
40048f6023SShuo Chen   return now;
41048f6023SShuo Chen }
42048f6023SShuo Chen 
43048f6023SShuo Chen void Poller::fillActiveChannels(int numEvents,
44048f6023SShuo Chen                                 ChannelList* activeChannels) const
45048f6023SShuo Chen {
46048f6023SShuo Chen   for (PollFdList::const_iterator pfd = pollfds_.begin();
47048f6023SShuo Chen       pfd != pollfds_.end() && numEvents > 0; ++pfd)
48048f6023SShuo Chen   {
49048f6023SShuo Chen     if (pfd->revents > 0)
50048f6023SShuo Chen     {
51048f6023SShuo Chen       --numEvents;
52048f6023SShuo Chen       ChannelMap::const_iterator ch = channels_.find(pfd->fd);
53048f6023SShuo Chen       assert(ch != channels_.end());
54048f6023SShuo Chen       Channel* channel = ch->second;
55048f6023SShuo Chen       assert(channel->fd() == pfd->fd);
56048f6023SShuo Chen       channel->set_revents(pfd->revents);
57048f6023SShuo Chen       // pfd->revents = 0;
58048f6023SShuo Chen       activeChannels->push_back(channel);
59048f6023SShuo Chen     }
60048f6023SShuo Chen   }
61048f6023SShuo Chen }
62048f6023SShuo Chen 
63048f6023SShuo Chen void Poller::updateChannel(Channel* channel)
64048f6023SShuo Chen {
65048f6023SShuo Chen   assertInLoopThread();
66048f6023SShuo Chen   LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events();
67b4a5ce52SShuo Chen   if (channel->index() < 0) {
68048f6023SShuo Chen     // a new one, add to pollfds_
69048f6023SShuo Chen     assert(channels_.find(channel->fd()) == channels_.end());
70048f6023SShuo Chen     struct pollfd pfd;
71048f6023SShuo Chen     pfd.fd = channel->fd();
72048f6023SShuo Chen     pfd.events = static_cast<short>(channel->events());
73048f6023SShuo Chen     pfd.revents = 0;
74048f6023SShuo Chen     pollfds_.push_back(pfd);
75048f6023SShuo Chen     int idx = static_cast<int>(pollfds_.size())-1;
76048f6023SShuo Chen     channel->set_index(idx);
77048f6023SShuo Chen     channels_[pfd.fd] = channel;
78b4a5ce52SShuo Chen   } else {
79048f6023SShuo Chen     // update existing one
80048f6023SShuo Chen     assert(channels_.find(channel->fd()) != channels_.end());
81048f6023SShuo Chen     assert(channels_[channel->fd()] == channel);
82048f6023SShuo Chen     int idx = channel->index();
83048f6023SShuo Chen     assert(0 <= idx && idx < static_cast<int>(pollfds_.size()));
84048f6023SShuo Chen     struct pollfd& pfd = pollfds_[idx];
85048f6023SShuo Chen!    assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1);
86048f6023SShuo Chen     pfd.events = static_cast<short>(channel->events());
87048f6023SShuo Chen     pfd.revents = 0;
88b4a5ce52SShuo Chen     if (channel->isNoneEvent()) {
89048f6023SShuo Chen       // ignore this pollfd
90048f6023SShuo Chen!      pfd.fd = -channel->fd()-1;
91048f6023SShuo Chen     }
92048f6023SShuo Chen   }
93048f6023SShuo Chen }
94048f6023SShuo Chen 
95048f6023SShuo Chen+void Poller::removeChannel(Channel* channel)
96048f6023SShuo Chen+{
97048f6023SShuo Chen+  assertInLoopThread();
98048f6023SShuo Chen+  LOG_TRACE << "fd = " << channel->fd();
99048f6023SShuo Chen+  assert(channels_.find(channel->fd()) != channels_.end());
100048f6023SShuo Chen+  assert(channels_[channel->fd()] == channel);
101048f6023SShuo Chen+  assert(channel->isNoneEvent());
102048f6023SShuo Chen+  int idx = channel->index();
103048f6023SShuo Chen+  assert(0 <= idx && idx < static_cast<int>(pollfds_.size()));
104048f6023SShuo Chen+  const struct pollfd& pfd = pollfds_[idx]; (void)pfd;
105048f6023SShuo Chen+  assert(pfd.fd == -channel->fd()-1 && pfd.events == channel->events());
106048f6023SShuo Chen+  size_t n = channels_.erase(channel->fd());
107048f6023SShuo Chen+  assert(n == 1); (void)n;
108b4a5ce52SShuo Chen+  if (implicit_cast<size_t>(idx) == pollfds_.size()-1) {
109048f6023SShuo Chen+    pollfds_.pop_back();
110b4a5ce52SShuo Chen+  } else {
111048f6023SShuo Chen+    int channelAtEnd = pollfds_.back().fd;
112048f6023SShuo Chen+    iter_swap(pollfds_.begin()+idx, pollfds_.end()-1);
113b4a5ce52SShuo Chen+    if (channelAtEnd < 0) {
114048f6023SShuo Chen+      channelAtEnd = -channelAtEnd-1;
115048f6023SShuo Chen+    }
116048f6023SShuo Chen+    channels_[channelAtEnd]->set_index(idx);
117048f6023SShuo Chen+    pollfds_.pop_back();
118048f6023SShuo Chen+  }
119048f6023SShuo Chen+}
120048f6023SShuo Chen+
121