TimerQueue.cc revision 344a2ce1
12745a763SShuo Chen// excerpts from http://code.google.com/p/muduo/
22745a763SShuo Chen//
32745a763SShuo Chen// Use of this source code is governed by a BSD-style license
42745a763SShuo Chen// that can be found in the License file.
52745a763SShuo Chen//
62745a763SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com)
72745a763SShuo Chen
82745a763SShuo Chen#define __STDC_LIMIT_MACROS
92745a763SShuo Chen#include "TimerQueue.h"
102745a763SShuo Chen
112745a763SShuo Chen#include "logging/Logging.h"
122745a763SShuo Chen#include "EventLoop.h"
132745a763SShuo Chen#include "Timer.h"
142745a763SShuo Chen#include "TimerId.h"
152745a763SShuo Chen
162745a763SShuo Chen#include <boost/bind.hpp>
172745a763SShuo Chen
182745a763SShuo Chen#include <sys/timerfd.h>
192745a763SShuo Chen
202745a763SShuo Chennamespace muduo
212745a763SShuo Chen{
222745a763SShuo Chennamespace detail
232745a763SShuo Chen{
242745a763SShuo Chen
252745a763SShuo Chenint createTimerfd()
262745a763SShuo Chen{
272745a763SShuo Chen  int timerfd = ::timerfd_create(CLOCK_MONOTONIC,
282745a763SShuo Chen                                 TFD_NONBLOCK | TFD_CLOEXEC);
292745a763SShuo Chen  if (timerfd < 0)
302745a763SShuo Chen  {
312745a763SShuo Chen    LOG_SYSFATAL << "Failed in timerfd_create";
322745a763SShuo Chen  }
332745a763SShuo Chen  return timerfd;
342745a763SShuo Chen}
352745a763SShuo Chen
362745a763SShuo Chenstruct timespec howMuchTimeFromNow(Timestamp when)
372745a763SShuo Chen{
382745a763SShuo Chen  int64_t microseconds = when.microSecondsSinceEpoch()
392745a763SShuo Chen                         - Timestamp::now().microSecondsSinceEpoch();
402745a763SShuo Chen  if (microseconds < 100)
412745a763SShuo Chen  {
422745a763SShuo Chen    microseconds = 100;
432745a763SShuo Chen  }
442745a763SShuo Chen  struct timespec ts;
452745a763SShuo Chen  ts.tv_sec = static_cast<time_t>(
462745a763SShuo Chen      microseconds / Timestamp::kMicroSecondsPerSecond);
472745a763SShuo Chen  ts.tv_nsec = static_cast<long>(
482745a763SShuo Chen      (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000);
492745a763SShuo Chen  return ts;
502745a763SShuo Chen}
512745a763SShuo Chen
522745a763SShuo Chenvoid readTimerfd(int timerfd, Timestamp now)
532745a763SShuo Chen{
542745a763SShuo Chen  uint64_t howmany;
552745a763SShuo Chen  ssize_t n = ::read(timerfd, &howmany, sizeof howmany);
562745a763SShuo Chen  LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString();
572745a763SShuo Chen  if (n != sizeof howmany)
582745a763SShuo Chen  {
592745a763SShuo Chen    LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8";
602745a763SShuo Chen  }
612745a763SShuo Chen}
622745a763SShuo Chen
632745a763SShuo Chenvoid resetTimerfd(int timerfd, Timestamp expiration)
642745a763SShuo Chen{
652745a763SShuo Chen  // wake up loop by timerfd_settime()
662745a763SShuo Chen  struct itimerspec newValue;
672745a763SShuo Chen  struct itimerspec oldValue;
682745a763SShuo Chen  bzero(&newValue, sizeof newValue);
692745a763SShuo Chen  bzero(&oldValue, sizeof oldValue);
702745a763SShuo Chen  newValue.it_value = howMuchTimeFromNow(expiration);
71b4a5ce52SShuo Chen  int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue);
722745a763SShuo Chen  if (ret)
732745a763SShuo Chen  {
742745a763SShuo Chen    LOG_SYSERR << "timerfd_settime()";
752745a763SShuo Chen  }
762745a763SShuo Chen}
772745a763SShuo Chen
782745a763SShuo Chen}
792745a763SShuo Chen}
802745a763SShuo Chen
812745a763SShuo Chenusing namespace muduo;
822745a763SShuo Chenusing namespace muduo::detail;
832745a763SShuo Chen
842745a763SShuo ChenTimerQueue::TimerQueue(EventLoop* loop)
852745a763SShuo Chen  : loop_(loop),
862745a763SShuo Chen    timerfd_(createTimerfd()),
872745a763SShuo Chen    timerfdChannel_(loop, timerfd_),
882745a763SShuo Chen    timers_()
892745a763SShuo Chen{
902745a763SShuo Chen  timerfdChannel_.setReadCallback(
912745a763SShuo Chen      boost::bind(&TimerQueue::handleRead, this));
922745a763SShuo Chen  // we are always reading the timerfd, we disarm it with timerfd_settime.
932745a763SShuo Chen  timerfdChannel_.enableReading();
942745a763SShuo Chen}
952745a763SShuo Chen
962745a763SShuo ChenTimerQueue::~TimerQueue()
972745a763SShuo Chen{
982745a763SShuo Chen  ::close(timerfd_);
992745a763SShuo Chen  // do not remove channel, since we're in EventLoop::dtor();
1002745a763SShuo Chen  for (TimerList::iterator it = timers_.begin();
1012745a763SShuo Chen      it != timers_.end(); ++it)
1022745a763SShuo Chen  {
1032745a763SShuo Chen    delete it->second;
1042745a763SShuo Chen  }
1052745a763SShuo Chen}
1062745a763SShuo Chen
1072745a763SShuo ChenTimerId TimerQueue::addTimer(const TimerCallback& cb,
1082745a763SShuo Chen                             Timestamp when,
1092745a763SShuo Chen                             double interval)
1102745a763SShuo Chen{
1112745a763SShuo Chen  Timer* timer = new Timer(cb, when, interval);
1122745a763SShuo Chen  loop_->runInLoop(
113344a2ce1SShuo Chen      boost::bind(&TimerQueue::addTimerInLoop, this, timer));
1142745a763SShuo Chen  return TimerId(timer);
1152745a763SShuo Chen}
1162745a763SShuo Chen
117344a2ce1SShuo Chenvoid TimerQueue::addTimerInLoop(Timer* timer)
1182745a763SShuo Chen{
1192745a763SShuo Chen  loop_->assertInLoopThread();
1202745a763SShuo Chen  bool earliestChanged = insert(timer);
1212745a763SShuo Chen
1222745a763SShuo Chen  if (earliestChanged)
1232745a763SShuo Chen  {
1242745a763SShuo Chen    resetTimerfd(timerfd_, timer->expiration());
1252745a763SShuo Chen  }
1262745a763SShuo Chen}
1272745a763SShuo Chen
1282745a763SShuo Chenvoid TimerQueue::handleRead()
1292745a763SShuo Chen{
1302745a763SShuo Chen  loop_->assertInLoopThread();
1312745a763SShuo Chen  Timestamp now(Timestamp::now());
1322745a763SShuo Chen  readTimerfd(timerfd_, now);
1332745a763SShuo Chen
1342745a763SShuo Chen  std::vector<Entry> expired = getExpired(now);
1352745a763SShuo Chen
1362745a763SShuo Chen  // safe to callback outside critical section
1372745a763SShuo Chen  for (std::vector<Entry>::iterator it = expired.begin();
1382745a763SShuo Chen      it != expired.end(); ++it)
1392745a763SShuo Chen  {
1402745a763SShuo Chen    it->second->run();
1412745a763SShuo Chen  }
1422745a763SShuo Chen
1432745a763SShuo Chen  reset(expired, now);
1442745a763SShuo Chen}
1452745a763SShuo Chen
1462745a763SShuo Chenstd::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now)
1472745a763SShuo Chen{
1482745a763SShuo Chen  std::vector<Entry> expired;
1492745a763SShuo Chen  Entry sentry = std::make_pair(now, reinterpret_cast<Timer*>(UINTPTR_MAX));
1502745a763SShuo Chen  TimerList::iterator it = timers_.lower_bound(sentry);
1512745a763SShuo Chen  assert(it == timers_.end() || now < it->first);
1522745a763SShuo Chen  std::copy(timers_.begin(), it, back_inserter(expired));
1532745a763SShuo Chen  timers_.erase(timers_.begin(), it);
1542745a763SShuo Chen
1552745a763SShuo Chen  return expired;
1562745a763SShuo Chen}
1572745a763SShuo Chen
1582745a763SShuo Chenvoid TimerQueue::reset(const std::vector<Entry>& expired, Timestamp now)
1592745a763SShuo Chen{
1602745a763SShuo Chen  Timestamp nextExpire;
1612745a763SShuo Chen
1622745a763SShuo Chen  for (std::vector<Entry>::const_iterator it = expired.begin();
1632745a763SShuo Chen      it != expired.end(); ++it)
1642745a763SShuo Chen  {
1652745a763SShuo Chen    if (it->second->repeat())
1662745a763SShuo Chen    {
1672745a763SShuo Chen      it->second->restart(now);
1682745a763SShuo Chen      insert(it->second);
1692745a763SShuo Chen    }
1702745a763SShuo Chen    else
1712745a763SShuo Chen    {
1722745a763SShuo Chen      // FIXME move to a free list
1732745a763SShuo Chen      delete it->second;
1742745a763SShuo Chen    }
1752745a763SShuo Chen  }
1762745a763SShuo Chen
1772745a763SShuo Chen  if (!timers_.empty())
1782745a763SShuo Chen  {
1792745a763SShuo Chen    nextExpire = timers_.begin()->second->expiration();
1802745a763SShuo Chen  }
1812745a763SShuo Chen
1822745a763SShuo Chen  if (nextExpire.valid())
1832745a763SShuo Chen  {
1842745a763SShuo Chen    resetTimerfd(timerfd_, nextExpire);
1852745a763SShuo Chen  }
1862745a763SShuo Chen}
1872745a763SShuo Chen
1882745a763SShuo Chenbool TimerQueue::insert(Timer* timer)
1892745a763SShuo Chen{
1902745a763SShuo Chen  bool earliestChanged = false;
1912745a763SShuo Chen  Timestamp when = timer->expiration();
1922745a763SShuo Chen  TimerList::iterator it = timers_.begin();
1932745a763SShuo Chen  if (it == timers_.end() || when < it->first)
1942745a763SShuo Chen  {
1952745a763SShuo Chen    earliestChanged = true;
1962745a763SShuo Chen  }
197a20e676dSShuo Chen  std::pair<TimerList::iterator, bool> result =
198a20e676dSShuo Chen          timers_.insert(std::make_pair(when, timer));
1992745a763SShuo Chen  assert(result.second);
2002745a763SShuo Chen  return earliestChanged;
2012745a763SShuo Chen}
2022745a763SShuo Chen
203