TimerQueue.cc revision 40161064
140161064SShuo Chen// excerpts from http://code.google.com/p/muduo/
240161064SShuo Chen//
340161064SShuo Chen// Use of this source code is governed by a BSD-style license
440161064SShuo Chen// that can be found in the License file.
540161064SShuo Chen//
640161064SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com)
740161064SShuo Chen
840161064SShuo Chen#define __STDC_LIMIT_MACROS
940161064SShuo Chen#include "TimerQueue.h"
1040161064SShuo Chen
1140161064SShuo Chen#include "logging/Logging.h"
1240161064SShuo Chen#include "EventLoop.h"
1340161064SShuo Chen#include "Timer.h"
1440161064SShuo Chen#include "TimerId.h"
1540161064SShuo Chen
1640161064SShuo Chen#include <boost/bind.hpp>
1740161064SShuo Chen
1840161064SShuo Chen#include <sys/timerfd.h>
1940161064SShuo Chen
2040161064SShuo Chennamespace muduo
2140161064SShuo Chen{
2240161064SShuo Chennamespace detail
2340161064SShuo Chen{
2440161064SShuo Chen
2540161064SShuo Chenint createTimerfd()
2640161064SShuo Chen{
2740161064SShuo Chen  int timerfd = ::timerfd_create(CLOCK_MONOTONIC,
2840161064SShuo Chen                                 TFD_NONBLOCK | TFD_CLOEXEC);
2940161064SShuo Chen  if (timerfd < 0)
3040161064SShuo Chen  {
3140161064SShuo Chen    LOG_SYSFATAL << "Failed in timerfd_create";
3240161064SShuo Chen  }
3340161064SShuo Chen  return timerfd;
3440161064SShuo Chen}
3540161064SShuo Chen
3640161064SShuo Chenstruct timespec howMuchTimeFromNow(Timestamp when)
3740161064SShuo Chen{
3840161064SShuo Chen  int64_t microseconds = when.microSecondsSinceEpoch()
3940161064SShuo Chen                         - Timestamp::now().microSecondsSinceEpoch();
4040161064SShuo Chen  if (microseconds < 100)
4140161064SShuo Chen  {
4240161064SShuo Chen    microseconds = 100;
4340161064SShuo Chen  }
4440161064SShuo Chen  struct timespec ts;
4540161064SShuo Chen  ts.tv_sec = static_cast<time_t>(
4640161064SShuo Chen      microseconds / Timestamp::kMicroSecondsPerSecond);
4740161064SShuo Chen  ts.tv_nsec = static_cast<long>(
4840161064SShuo Chen      (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000);
4940161064SShuo Chen  return ts;
5040161064SShuo Chen}
5140161064SShuo Chen
5240161064SShuo Chenvoid readTimerfd(int timerfd, Timestamp now)
5340161064SShuo Chen{
5440161064SShuo Chen  uint64_t howmany;
5540161064SShuo Chen  ssize_t n = ::read(timerfd, &howmany, sizeof howmany);
5640161064SShuo Chen  LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString();
5740161064SShuo Chen  if (n != sizeof howmany)
5840161064SShuo Chen  {
5940161064SShuo Chen    LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8";
6040161064SShuo Chen  }
6140161064SShuo Chen}
6240161064SShuo Chen
6340161064SShuo Chenvoid resetTimerfd(int timerfd, Timestamp expiration)
6440161064SShuo Chen{
6540161064SShuo Chen  // wake up loop by timerfd_settime()
6640161064SShuo Chen  struct itimerspec newValue;
6740161064SShuo Chen  struct itimerspec oldValue;
6840161064SShuo Chen  bzero(&newValue, sizeof newValue);
6940161064SShuo Chen  bzero(&oldValue, sizeof oldValue);
7040161064SShuo Chen  newValue.it_value = howMuchTimeFromNow(expiration);
7140161064SShuo Chen  int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue);
7240161064SShuo Chen  if (ret)
7340161064SShuo Chen  {
7440161064SShuo Chen    LOG_SYSERR << "timerfd_settime()";
7540161064SShuo Chen  }
7640161064SShuo Chen}
7740161064SShuo Chen
7840161064SShuo Chen}
7940161064SShuo Chen}
8040161064SShuo Chen
8140161064SShuo Chenusing namespace muduo;
8240161064SShuo Chenusing namespace muduo::detail;
8340161064SShuo Chen
8440161064SShuo ChenTimerQueue::TimerQueue(EventLoop* loop)
8540161064SShuo Chen  : loop_(loop),
8640161064SShuo Chen    timerfd_(createTimerfd()),
8740161064SShuo Chen    timerfdChannel_(loop, timerfd_),
8840161064SShuo Chen    timers_()
8940161064SShuo Chen{
9040161064SShuo Chen  timerfdChannel_.setReadCallback(
9140161064SShuo Chen      boost::bind(&TimerQueue::handleRead, this));
9240161064SShuo Chen  // we are always reading the timerfd, we disarm it with timerfd_settime.
9340161064SShuo Chen  timerfdChannel_.enableReading();
9440161064SShuo Chen}
9540161064SShuo Chen
9640161064SShuo ChenTimerQueue::~TimerQueue()
9740161064SShuo Chen{
9840161064SShuo Chen  ::close(timerfd_);
9940161064SShuo Chen  // do not remove channel, since we're in EventLoop::dtor();
10040161064SShuo Chen  for (TimerList::iterator it = timers_.begin();
10140161064SShuo Chen      it != timers_.end(); ++it)
10240161064SShuo Chen  {
10340161064SShuo Chen    delete it->second;
10440161064SShuo Chen  }
10540161064SShuo Chen}
10640161064SShuo Chen
10740161064SShuo ChenTimerId TimerQueue::addTimer(const TimerCallback& cb,
10840161064SShuo Chen                             Timestamp when,
10940161064SShuo Chen                             double interval)
11040161064SShuo Chen{
11140161064SShuo Chen  Timer* timer = new Timer(cb, when, interval);
11240161064SShuo Chen  loop_->runInLoop(
11340161064SShuo Chen      boost::bind(&TimerQueue::scheduleInLoop, this, timer));
11440161064SShuo Chen  return TimerId(timer);
11540161064SShuo Chen}
11640161064SShuo Chen
11740161064SShuo Chenvoid TimerQueue::scheduleInLoop(Timer* timer)
11840161064SShuo Chen{
11940161064SShuo Chen  loop_->assertInLoopThread();
12040161064SShuo Chen  bool earliestChanged = insert(timer);
12140161064SShuo Chen
12240161064SShuo Chen  if (earliestChanged)
12340161064SShuo Chen  {
12440161064SShuo Chen    resetTimerfd(timerfd_, timer->expiration());
12540161064SShuo Chen  }
12640161064SShuo Chen}
12740161064SShuo Chen
12840161064SShuo Chenvoid TimerQueue::handleRead()
12940161064SShuo Chen{
13040161064SShuo Chen  loop_->assertInLoopThread();
13140161064SShuo Chen  Timestamp now(Timestamp::now());
13240161064SShuo Chen  readTimerfd(timerfd_, now);
13340161064SShuo Chen
13440161064SShuo Chen  std::vector<Entry> expired = getExpired(now);
13540161064SShuo Chen
13640161064SShuo Chen  // safe to callback outside critical section
13740161064SShuo Chen  for (std::vector<Entry>::iterator it = expired.begin();
13840161064SShuo Chen      it != expired.end(); ++it)
13940161064SShuo Chen  {
14040161064SShuo Chen    it->second->run();
14140161064SShuo Chen  }
14240161064SShuo Chen
14340161064SShuo Chen  reset(expired, now);
14440161064SShuo Chen}
14540161064SShuo Chen
14640161064SShuo Chenstd::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now)
14740161064SShuo Chen{
14840161064SShuo Chen  std::vector<Entry> expired;
14940161064SShuo Chen  Entry sentry = std::make_pair(now, reinterpret_cast<Timer*>(UINTPTR_MAX));
15040161064SShuo Chen  TimerList::iterator it = timers_.lower_bound(sentry);
15140161064SShuo Chen  assert(it == timers_.end() || now < it->first);
15240161064SShuo Chen  std::copy(timers_.begin(), it, back_inserter(expired));
15340161064SShuo Chen  timers_.erase(timers_.begin(), it);
15440161064SShuo Chen
15540161064SShuo Chen  return expired;
15640161064SShuo Chen}
15740161064SShuo Chen
15840161064SShuo Chenvoid TimerQueue::reset(const std::vector<Entry>& expired, Timestamp now)
15940161064SShuo Chen{
16040161064SShuo Chen  Timestamp nextExpire;
16140161064SShuo Chen
16240161064SShuo Chen  for (std::vector<Entry>::const_iterator it = expired.begin();
16340161064SShuo Chen      it != expired.end(); ++it)
16440161064SShuo Chen  {
16540161064SShuo Chen    if (it->second->repeat())
16640161064SShuo Chen    {
16740161064SShuo Chen      it->second->restart(now);
16840161064SShuo Chen      insert(it->second);
16940161064SShuo Chen    }
17040161064SShuo Chen    else
17140161064SShuo Chen    {
17240161064SShuo Chen      // FIXME move to a free list
17340161064SShuo Chen      delete it->second;
17440161064SShuo Chen    }
17540161064SShuo Chen  }
17640161064SShuo Chen
17740161064SShuo Chen  if (!timers_.empty())
17840161064SShuo Chen  {
17940161064SShuo Chen    nextExpire = timers_.begin()->second->expiration();
18040161064SShuo Chen  }
18140161064SShuo Chen
18240161064SShuo Chen  if (nextExpire.valid())
18340161064SShuo Chen  {
18440161064SShuo Chen    resetTimerfd(timerfd_, nextExpire);
18540161064SShuo Chen  }
18640161064SShuo Chen}
18740161064SShuo Chen
18840161064SShuo Chenbool TimerQueue::insert(Timer* timer)
18940161064SShuo Chen{
19040161064SShuo Chen  bool earliestChanged = false;
19140161064SShuo Chen  Timestamp when = timer->expiration();
19240161064SShuo Chen  TimerList::iterator it = timers_.begin();
19340161064SShuo Chen  if (it == timers_.end() || when < it->first)
19440161064SShuo Chen  {
19540161064SShuo Chen    earliestChanged = true;
19640161064SShuo Chen  }
19740161064SShuo Chen  std::pair<TimerList::iterator, bool> result =
19840161064SShuo Chen          timers_.insert(std::make_pair(when, timer));
19940161064SShuo Chen  assert(result.second);
20040161064SShuo Chen  return earliestChanged;
20140161064SShuo Chen}
20240161064SShuo Chen
203