170523619SShuo Chen// excerpts from http://code.google.com/p/muduo/
270523619SShuo Chen//
370523619SShuo Chen// Use of this source code is governed by a BSD-style license
470523619SShuo Chen// that can be found in the License file.
570523619SShuo Chen//
670523619SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com)
770523619SShuo Chen
870523619SShuo Chen#include "EPoller.h"
970523619SShuo Chen
1070523619SShuo Chen#include "Channel.h"
1170523619SShuo Chen#include "logging/Logging.h"
1270523619SShuo Chen
1370523619SShuo Chen
1470523619SShuo Chen#include <boost/static_assert.hpp>
1570523619SShuo Chen
1670523619SShuo Chen#include <assert.h>
1770523619SShuo Chen#include <errno.h>
1870523619SShuo Chen#include <poll.h>
1970523619SShuo Chen#include <sys/epoll.h>
2070523619SShuo Chen
2170523619SShuo Chenusing namespace muduo;
2270523619SShuo Chen
2370523619SShuo Chen// On Linux, the constants of poll(2) and epoll(4)
2470523619SShuo Chen// are expected to be the same.
2570523619SShuo ChenBOOST_STATIC_ASSERT(EPOLLIN == POLLIN);
2670523619SShuo ChenBOOST_STATIC_ASSERT(EPOLLPRI == POLLPRI);
2770523619SShuo ChenBOOST_STATIC_ASSERT(EPOLLOUT == POLLOUT);
2870523619SShuo ChenBOOST_STATIC_ASSERT(EPOLLRDHUP == POLLRDHUP);
2970523619SShuo ChenBOOST_STATIC_ASSERT(EPOLLERR == POLLERR);
3070523619SShuo ChenBOOST_STATIC_ASSERT(EPOLLHUP == POLLHUP);
3170523619SShuo Chen
3270523619SShuo Chennamespace
3370523619SShuo Chen{
3470523619SShuo Chenconst int kNew = -1;
3570523619SShuo Chenconst int kAdded = 1;
3670523619SShuo Chenconst int kDeleted = 2;
3770523619SShuo Chen}
3870523619SShuo Chen
3970523619SShuo ChenEPoller::EPoller(EventLoop* loop)
4070523619SShuo Chen  : ownerLoop_(loop),
4170523619SShuo Chen    epollfd_(::epoll_create1(EPOLL_CLOEXEC)),
4270523619SShuo Chen    events_(kInitEventListSize)
4370523619SShuo Chen{
4470523619SShuo Chen  if (epollfd_ < 0)
4570523619SShuo Chen  {
4670523619SShuo Chen    LOG_SYSFATAL << "EPoller::EPoller";
4770523619SShuo Chen  }
4870523619SShuo Chen}
4970523619SShuo Chen
5070523619SShuo ChenEPoller::~EPoller()
5170523619SShuo Chen{
5270523619SShuo Chen  ::close(epollfd_);
5370523619SShuo Chen}
5470523619SShuo Chen
5570523619SShuo ChenTimestamp EPoller::poll(int timeoutMs, ChannelList* activeChannels)
5670523619SShuo Chen{
5770523619SShuo Chen  int numEvents = ::epoll_wait(epollfd_,
5870523619SShuo Chen                               &*events_.begin(),
5970523619SShuo Chen                               static_cast<int>(events_.size()),
6070523619SShuo Chen                               timeoutMs);
6170523619SShuo Chen  Timestamp now(Timestamp::now());
6270523619SShuo Chen  if (numEvents > 0)
6370523619SShuo Chen  {
6470523619SShuo Chen    LOG_TRACE << numEvents << " events happended";
6570523619SShuo Chen    fillActiveChannels(numEvents, activeChannels);
6670523619SShuo Chen    if (implicit_cast<size_t>(numEvents) == events_.size())
6770523619SShuo Chen    {
6870523619SShuo Chen      events_.resize(events_.size()*2);
6970523619SShuo Chen    }
7070523619SShuo Chen  }
7170523619SShuo Chen  else if (numEvents == 0)
7270523619SShuo Chen  {
7370523619SShuo Chen    LOG_TRACE << " nothing happended";
7470523619SShuo Chen  }
7570523619SShuo Chen  else
7670523619SShuo Chen  {
7770523619SShuo Chen    LOG_SYSERR << "EPoller::poll()";
7870523619SShuo Chen  }
7970523619SShuo Chen  return now;
8070523619SShuo Chen}
8170523619SShuo Chen
8270523619SShuo Chenvoid EPoller::fillActiveChannels(int numEvents,
83614bbdb4SShuo Chen                                 ChannelList* activeChannels) const
8470523619SShuo Chen{
8570523619SShuo Chen  assert(implicit_cast<size_t>(numEvents) <= events_.size());
8670523619SShuo Chen  for (int i = 0; i < numEvents; ++i)
8770523619SShuo Chen  {
8870523619SShuo Chen    Channel* channel = static_cast<Channel*>(events_[i].data.ptr);
8970523619SShuo Chen#ifndef NDEBUG
9070523619SShuo Chen    int fd = channel->fd();
9170523619SShuo Chen    ChannelMap::const_iterator it = channels_.find(fd);
9270523619SShuo Chen    assert(it != channels_.end());
9370523619SShuo Chen    assert(it->second == channel);
9470523619SShuo Chen#endif
9570523619SShuo Chen    channel->set_revents(events_[i].events);
9670523619SShuo Chen    activeChannels->push_back(channel);
9770523619SShuo Chen  }
9870523619SShuo Chen}
9970523619SShuo Chen
10070523619SShuo Chenvoid EPoller::updateChannel(Channel* channel)
10170523619SShuo Chen{
10270523619SShuo Chen  assertInLoopThread();
10370523619SShuo Chen  LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events();
10470523619SShuo Chen  const int index = channel->index();
10570523619SShuo Chen  if (index == kNew || index == kDeleted)
10670523619SShuo Chen  {
10770523619SShuo Chen    // a new one, add with EPOLL_CTL_ADD
10870523619SShuo Chen    int fd = channel->fd();
10970523619SShuo Chen    if (index == kNew)
11070523619SShuo Chen    {
11170523619SShuo Chen      assert(channels_.find(fd) == channels_.end());
11270523619SShuo Chen      channels_[fd] = channel;
11370523619SShuo Chen    }
11470523619SShuo Chen    else // index == kDeleted
11570523619SShuo Chen    {
11670523619SShuo Chen      assert(channels_.find(fd) != channels_.end());
11770523619SShuo Chen      assert(channels_[fd] == channel);
11870523619SShuo Chen    }
11970523619SShuo Chen    channel->set_index(kAdded);
12070523619SShuo Chen    update(EPOLL_CTL_ADD, channel);
12170523619SShuo Chen  }
12270523619SShuo Chen  else
12370523619SShuo Chen  {
12470523619SShuo Chen    // update existing one with EPOLL_CTL_MOD/DEL
12570523619SShuo Chen    int fd = channel->fd();
12670523619SShuo Chen    (void)fd;
12770523619SShuo Chen    assert(channels_.find(fd) != channels_.end());
12870523619SShuo Chen    assert(channels_[fd] == channel);
12970523619SShuo Chen    assert(index == kAdded);
13070523619SShuo Chen    if (channel->isNoneEvent())
13170523619SShuo Chen    {
13270523619SShuo Chen      update(EPOLL_CTL_DEL, channel);
13370523619SShuo Chen      channel->set_index(kDeleted);
13470523619SShuo Chen    }
13570523619SShuo Chen    else
13670523619SShuo Chen    {
13770523619SShuo Chen      update(EPOLL_CTL_MOD, channel);
13870523619SShuo Chen    }
13970523619SShuo Chen  }
14070523619SShuo Chen}
14170523619SShuo Chen
14270523619SShuo Chenvoid EPoller::removeChannel(Channel* channel)
14370523619SShuo Chen{
14470523619SShuo Chen  assertInLoopThread();
14570523619SShuo Chen  int fd = channel->fd();
14670523619SShuo Chen  LOG_TRACE << "fd = " << fd;
14770523619SShuo Chen  assert(channels_.find(fd) != channels_.end());
14870523619SShuo Chen  assert(channels_[fd] == channel);
14970523619SShuo Chen  assert(channel->isNoneEvent());
15070523619SShuo Chen  int index = channel->index();
15170523619SShuo Chen  assert(index == kAdded || index == kDeleted);
15270523619SShuo Chen  size_t n = channels_.erase(fd);
15370523619SShuo Chen  (void)n;
15470523619SShuo Chen  assert(n == 1);
15570523619SShuo Chen
15670523619SShuo Chen  if (index == kAdded)
15770523619SShuo Chen  {
15870523619SShuo Chen    update(EPOLL_CTL_DEL, channel);
15970523619SShuo Chen  }
16070523619SShuo Chen  channel->set_index(kNew);
16170523619SShuo Chen}
16270523619SShuo Chen
16370523619SShuo Chenvoid EPoller::update(int operation, Channel* channel)
16470523619SShuo Chen{
16570523619SShuo Chen  struct epoll_event event;
16670523619SShuo Chen  bzero(&event, sizeof event);
16770523619SShuo Chen  event.events = channel->events();
16870523619SShuo Chen  event.data.ptr = channel;
16970523619SShuo Chen  int fd = channel->fd();
17070523619SShuo Chen  if (::epoll_ctl(epollfd_, operation, fd, &event) < 0)
17170523619SShuo Chen  {
17270523619SShuo Chen    if (operation == EPOLL_CTL_DEL)
17370523619SShuo Chen    {
17470523619SShuo Chen      LOG_SYSERR << "epoll_ctl op=" << operation << " fd=" << fd;
17570523619SShuo Chen    }
17670523619SShuo Chen    else
17770523619SShuo Chen    {
17870523619SShuo Chen      LOG_SYSFATAL << "epoll_ctl op=" << operation << " fd=" << fd;
17970523619SShuo Chen    }
18070523619SShuo Chen  }
18170523619SShuo Chen}
18270523619SShuo Chen
183