TimerQueue.cc revision b4a5ce52
142bf2220SShuo Chen// excerpts from http://code.google.com/p/muduo/
242bf2220SShuo Chen//
342bf2220SShuo Chen// Use of this source code is governed by a BSD-style license
442bf2220SShuo Chen// that can be found in the License file.
542bf2220SShuo Chen//
642bf2220SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com)
742bf2220SShuo Chen
842bf2220SShuo Chen#define __STDC_LIMIT_MACROS
942bf2220SShuo Chen#include "TimerQueue.h"
1042bf2220SShuo Chen
1142bf2220SShuo Chen#include "logging/Logging.h"
1242bf2220SShuo Chen#include "EventLoop.h"
1342bf2220SShuo Chen#include "Timer.h"
1442bf2220SShuo Chen#include "TimerId.h"
1542bf2220SShuo Chen
1642bf2220SShuo Chen#include <boost/bind.hpp>
1742bf2220SShuo Chen
1842bf2220SShuo Chen#include <sys/timerfd.h>
1942bf2220SShuo Chen
2042bf2220SShuo Chennamespace muduo
2142bf2220SShuo Chen{
2242bf2220SShuo Chennamespace detail
2342bf2220SShuo Chen{
2442bf2220SShuo Chen
2542bf2220SShuo Chenint createTimerfd()
2642bf2220SShuo Chen{
2742bf2220SShuo Chen  int timerfd = ::timerfd_create(CLOCK_MONOTONIC,
2842bf2220SShuo Chen                                 TFD_NONBLOCK | TFD_CLOEXEC);
2942bf2220SShuo Chen  if (timerfd < 0)
3042bf2220SShuo Chen  {
3142bf2220SShuo Chen    LOG_SYSFATAL << "Failed in timerfd_create";
3242bf2220SShuo Chen  }
3342bf2220SShuo Chen  return timerfd;
3442bf2220SShuo Chen}
3542bf2220SShuo Chen
3642bf2220SShuo Chenstruct timespec howMuchTimeFromNow(Timestamp when)
3742bf2220SShuo Chen{
3842bf2220SShuo Chen  int64_t microseconds = when.microSecondsSinceEpoch()
3942bf2220SShuo Chen                         - Timestamp::now().microSecondsSinceEpoch();
4042bf2220SShuo Chen  if (microseconds < 100)
4142bf2220SShuo Chen  {
4242bf2220SShuo Chen    microseconds = 100;
4342bf2220SShuo Chen  }
4442bf2220SShuo Chen  struct timespec ts;
4542bf2220SShuo Chen  ts.tv_sec = static_cast<time_t>(
4642bf2220SShuo Chen      microseconds / Timestamp::kMicroSecondsPerSecond);
4742bf2220SShuo Chen  ts.tv_nsec = static_cast<long>(
4842bf2220SShuo Chen      (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000);
4942bf2220SShuo Chen  return ts;
5042bf2220SShuo Chen}
5142bf2220SShuo Chen
5242bf2220SShuo Chenvoid readTimerfd(int timerfd, Timestamp now)
5342bf2220SShuo Chen{
5442bf2220SShuo Chen  uint64_t howmany;
5542bf2220SShuo Chen  ssize_t n = ::read(timerfd, &howmany, sizeof howmany);
5642bf2220SShuo Chen  LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString();
5742bf2220SShuo Chen  if (n != sizeof howmany)
5842bf2220SShuo Chen  {
5942bf2220SShuo Chen    LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8";
6042bf2220SShuo Chen  }
6142bf2220SShuo Chen}
6242bf2220SShuo Chen
6342bf2220SShuo Chenvoid resetTimerfd(int timerfd, Timestamp expiration)
6442bf2220SShuo Chen{
6542bf2220SShuo Chen  // wake up loop by timerfd_settime()
6642bf2220SShuo Chen  struct itimerspec newValue;
6742bf2220SShuo Chen  struct itimerspec oldValue;
6842bf2220SShuo Chen  bzero(&newValue, sizeof newValue);
6942bf2220SShuo Chen  bzero(&oldValue, sizeof oldValue);
7042bf2220SShuo Chen  newValue.it_value = howMuchTimeFromNow(expiration);
71b4a5ce52SShuo Chen  int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue);
7242bf2220SShuo Chen  if (ret)
7342bf2220SShuo Chen  {
7442bf2220SShuo Chen    LOG_SYSERR << "timerfd_settime()";
7542bf2220SShuo Chen  }
7642bf2220SShuo Chen}
7742bf2220SShuo Chen
7842bf2220SShuo Chen}
7942bf2220SShuo Chen}
8042bf2220SShuo Chen
8142bf2220SShuo Chenusing namespace muduo;
8242bf2220SShuo Chenusing namespace muduo::detail;
8342bf2220SShuo Chen
8442bf2220SShuo ChenTimerQueue::TimerQueue(EventLoop* loop)
8542bf2220SShuo Chen  : loop_(loop),
8642bf2220SShuo Chen    timerfd_(createTimerfd()),
8742bf2220SShuo Chen    timerfdChannel_(loop, timerfd_),
8842bf2220SShuo Chen    timers_()
8942bf2220SShuo Chen{
9042bf2220SShuo Chen  timerfdChannel_.setReadCallback(
9142bf2220SShuo Chen      boost::bind(&TimerQueue::handleRead, this));
9242bf2220SShuo Chen  // we are always reading the timerfd, we disarm it with timerfd_settime.
9342bf2220SShuo Chen  timerfdChannel_.enableReading();
9442bf2220SShuo Chen}
9542bf2220SShuo Chen
9642bf2220SShuo ChenTimerQueue::~TimerQueue()
9742bf2220SShuo Chen{
9842bf2220SShuo Chen  ::close(timerfd_);
9942bf2220SShuo Chen  // do not remove channel, since we're in EventLoop::dtor();
10042bf2220SShuo Chen  for (TimerList::iterator it = timers_.begin();
10142bf2220SShuo Chen      it != timers_.end(); ++it)
10242bf2220SShuo Chen  {
10342bf2220SShuo Chen    delete it->second;
10442bf2220SShuo Chen  }
10542bf2220SShuo Chen}
10642bf2220SShuo Chen
10742bf2220SShuo ChenTimerId TimerQueue::addTimer(const TimerCallback& cb,
10842bf2220SShuo Chen                             Timestamp when,
10942bf2220SShuo Chen                             double interval)
11042bf2220SShuo Chen{
11142bf2220SShuo Chen  Timer* timer = new Timer(cb, when, interval);
11242bf2220SShuo Chen  loop_->assertInLoopThread();
11342bf2220SShuo Chen  bool earliestChanged = insert(timer);
11442bf2220SShuo Chen
11542bf2220SShuo Chen  if (earliestChanged)
11642bf2220SShuo Chen  {
11742bf2220SShuo Chen    resetTimerfd(timerfd_, timer->expiration());
11842bf2220SShuo Chen  }
11942bf2220SShuo Chen  return TimerId(timer);
12042bf2220SShuo Chen}
12142bf2220SShuo Chen
12242bf2220SShuo Chenvoid TimerQueue::handleRead()
12342bf2220SShuo Chen{
12442bf2220SShuo Chen  loop_->assertInLoopThread();
12542bf2220SShuo Chen  Timestamp now(Timestamp::now());
12642bf2220SShuo Chen  readTimerfd(timerfd_, now);
12742bf2220SShuo Chen
12842bf2220SShuo Chen  std::vector<Entry> expired = getExpired(now);
12942bf2220SShuo Chen
13042bf2220SShuo Chen  // safe to callback outside critical section
13142bf2220SShuo Chen  for (std::vector<Entry>::iterator it = expired.begin();
13242bf2220SShuo Chen      it != expired.end(); ++it)
13342bf2220SShuo Chen  {
13442bf2220SShuo Chen    it->second->run();
13542bf2220SShuo Chen  }
13642bf2220SShuo Chen
13742bf2220SShuo Chen  reset(expired, now);
13842bf2220SShuo Chen}
13942bf2220SShuo Chen
14042bf2220SShuo Chenstd::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now)
14142bf2220SShuo Chen{
14242bf2220SShuo Chen  std::vector<Entry> expired;
14342bf2220SShuo Chen  Entry sentry = std::make_pair(now, reinterpret_cast<Timer*>(UINTPTR_MAX));
14442bf2220SShuo Chen  TimerList::iterator it = timers_.lower_bound(sentry);
14542bf2220SShuo Chen  assert(it == timers_.end() || now < it->first);
14642bf2220SShuo Chen  std::copy(timers_.begin(), it, back_inserter(expired));
14742bf2220SShuo Chen  timers_.erase(timers_.begin(), it);
14842bf2220SShuo Chen
14942bf2220SShuo Chen  return expired;
15042bf2220SShuo Chen}
15142bf2220SShuo Chen
15242bf2220SShuo Chenvoid TimerQueue::reset(const std::vector<Entry>& expired, Timestamp now)
15342bf2220SShuo Chen{
15442bf2220SShuo Chen  Timestamp nextExpire;
15542bf2220SShuo Chen
15642bf2220SShuo Chen  for (std::vector<Entry>::const_iterator it = expired.begin();
15742bf2220SShuo Chen      it != expired.end(); ++it)
15842bf2220SShuo Chen  {
15942bf2220SShuo Chen    if (it->second->repeat())
16042bf2220SShuo Chen    {
16142bf2220SShuo Chen      it->second->restart(now);
16242bf2220SShuo Chen      insert(it->second);
16342bf2220SShuo Chen    }
16442bf2220SShuo Chen    else
16542bf2220SShuo Chen    {
16642bf2220SShuo Chen      // FIXME move to a free list
16742bf2220SShuo Chen      delete it->second;
16842bf2220SShuo Chen    }
16942bf2220SShuo Chen  }
17042bf2220SShuo Chen
17142bf2220SShuo Chen  if (!timers_.empty())
17242bf2220SShuo Chen  {
17342bf2220SShuo Chen    nextExpire = timers_.begin()->second->expiration();
17442bf2220SShuo Chen  }
17542bf2220SShuo Chen
17642bf2220SShuo Chen  if (nextExpire.valid())
17742bf2220SShuo Chen  {
17842bf2220SShuo Chen    resetTimerfd(timerfd_, nextExpire);
17942bf2220SShuo Chen  }
18042bf2220SShuo Chen}
18142bf2220SShuo Chen
18242bf2220SShuo Chenbool TimerQueue::insert(Timer* timer)
18342bf2220SShuo Chen{
18442bf2220SShuo Chen  bool earliestChanged = false;
18542bf2220SShuo Chen  Timestamp when = timer->expiration();
18642bf2220SShuo Chen  TimerList::iterator it = timers_.begin();
18742bf2220SShuo Chen  if (it == timers_.end() || when < it->first)
18842bf2220SShuo Chen  {
18942bf2220SShuo Chen    earliestChanged = true;
19042bf2220SShuo Chen  }
191a20e676dSShuo Chen  std::pair<TimerList::iterator, bool> result =
192a20e676dSShuo Chen          timers_.insert(std::make_pair(when, timer));
19342bf2220SShuo Chen  assert(result.second);
19442bf2220SShuo Chen  return earliestChanged;
19542bf2220SShuo Chen}
19642bf2220SShuo Chen
197