1bfe73648SShuo Chen// excerpts from http://code.google.com/p/muduo/
2bfe73648SShuo Chen//
3bfe73648SShuo Chen// Use of this source code is governed by a BSD-style license
4bfe73648SShuo Chen// that can be found in the License file.
5bfe73648SShuo Chen//
6bfe73648SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com)
7bfe73648SShuo Chen
8bfe73648SShuo Chen#define __STDC_LIMIT_MACROS
9bfe73648SShuo Chen#include "TimerQueue.h"
10bfe73648SShuo Chen
11bfe73648SShuo Chen#include "logging/Logging.h"
12bfe73648SShuo Chen#include "EventLoop.h"
13bfe73648SShuo Chen#include "Timer.h"
14bfe73648SShuo Chen#include "TimerId.h"
15bfe73648SShuo Chen
16bfe73648SShuo Chen#include <boost/bind.hpp>
17bfe73648SShuo Chen
18bfe73648SShuo Chen#include <sys/timerfd.h>
19bfe73648SShuo Chen
20bfe73648SShuo Chennamespace muduo
21bfe73648SShuo Chen{
22bfe73648SShuo Chennamespace detail
23bfe73648SShuo Chen{
24bfe73648SShuo Chen
25bfe73648SShuo Chenint createTimerfd()
26bfe73648SShuo Chen{
27bfe73648SShuo Chen  int timerfd = ::timerfd_create(CLOCK_MONOTONIC,
28bfe73648SShuo Chen                                 TFD_NONBLOCK | TFD_CLOEXEC);
29bfe73648SShuo Chen  if (timerfd < 0)
30bfe73648SShuo Chen  {
31bfe73648SShuo Chen    LOG_SYSFATAL << "Failed in timerfd_create";
32bfe73648SShuo Chen  }
33bfe73648SShuo Chen  return timerfd;
34bfe73648SShuo Chen}
35bfe73648SShuo Chen
36bfe73648SShuo Chenstruct timespec howMuchTimeFromNow(Timestamp when)
37bfe73648SShuo Chen{
38bfe73648SShuo Chen  int64_t microseconds = when.microSecondsSinceEpoch()
39bfe73648SShuo Chen                         - Timestamp::now().microSecondsSinceEpoch();
40bfe73648SShuo Chen  if (microseconds < 100)
41bfe73648SShuo Chen  {
42bfe73648SShuo Chen    microseconds = 100;
43bfe73648SShuo Chen  }
44bfe73648SShuo Chen  struct timespec ts;
45bfe73648SShuo Chen  ts.tv_sec = static_cast<time_t>(
46bfe73648SShuo Chen      microseconds / Timestamp::kMicroSecondsPerSecond);
47bfe73648SShuo Chen  ts.tv_nsec = static_cast<long>(
48bfe73648SShuo Chen      (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000);
49bfe73648SShuo Chen  return ts;
50bfe73648SShuo Chen}
51bfe73648SShuo Chen
52bfe73648SShuo Chenvoid readTimerfd(int timerfd, Timestamp now)
53bfe73648SShuo Chen{
54bfe73648SShuo Chen  uint64_t howmany;
55bfe73648SShuo Chen  ssize_t n = ::read(timerfd, &howmany, sizeof howmany);
56bfe73648SShuo Chen  LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString();
57bfe73648SShuo Chen  if (n != sizeof howmany)
58bfe73648SShuo Chen  {
59bfe73648SShuo Chen    LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8";
60bfe73648SShuo Chen  }
61bfe73648SShuo Chen}
62bfe73648SShuo Chen
63bfe73648SShuo Chenvoid resetTimerfd(int timerfd, Timestamp expiration)
64bfe73648SShuo Chen{
65bfe73648SShuo Chen  // wake up loop by timerfd_settime()
66bfe73648SShuo Chen  struct itimerspec newValue;
67bfe73648SShuo Chen  struct itimerspec oldValue;
68bfe73648SShuo Chen  bzero(&newValue, sizeof newValue);
69bfe73648SShuo Chen  bzero(&oldValue, sizeof oldValue);
70bfe73648SShuo Chen  newValue.it_value = howMuchTimeFromNow(expiration);
71b4a5ce52SShuo Chen  int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue);
72bfe73648SShuo Chen  if (ret)
73bfe73648SShuo Chen  {
74bfe73648SShuo Chen    LOG_SYSERR << "timerfd_settime()";
75bfe73648SShuo Chen  }
76bfe73648SShuo Chen}
77bfe73648SShuo Chen
78bfe73648SShuo Chen}
79bfe73648SShuo Chen}
80bfe73648SShuo Chen
81bfe73648SShuo Chenusing namespace muduo;
82bfe73648SShuo Chenusing namespace muduo::detail;
83bfe73648SShuo Chen
84bfe73648SShuo ChenTimerQueue::TimerQueue(EventLoop* loop)
85bfe73648SShuo Chen  : loop_(loop),
86bfe73648SShuo Chen    timerfd_(createTimerfd()),
87bfe73648SShuo Chen    timerfdChannel_(loop, timerfd_),
88bfe73648SShuo Chen    timers_()
89bfe73648SShuo Chen{
90bfe73648SShuo Chen  timerfdChannel_.setReadCallback(
91bfe73648SShuo Chen      boost::bind(&TimerQueue::handleRead, this));
92bfe73648SShuo Chen  // we are always reading the timerfd, we disarm it with timerfd_settime.
93bfe73648SShuo Chen  timerfdChannel_.enableReading();
94bfe73648SShuo Chen}
95bfe73648SShuo Chen
96bfe73648SShuo ChenTimerQueue::~TimerQueue()
97bfe73648SShuo Chen{
98bfe73648SShuo Chen  ::close(timerfd_);
99bfe73648SShuo Chen  // do not remove channel, since we're in EventLoop::dtor();
100bfe73648SShuo Chen  for (TimerList::iterator it = timers_.begin();
101bfe73648SShuo Chen      it != timers_.end(); ++it)
102bfe73648SShuo Chen  {
103bfe73648SShuo Chen    delete it->second;
104bfe73648SShuo Chen  }
105bfe73648SShuo Chen}
106bfe73648SShuo Chen
107bfe73648SShuo ChenTimerId TimerQueue::addTimer(const TimerCallback& cb,
108bfe73648SShuo Chen                             Timestamp when,
109bfe73648SShuo Chen                             double interval)
110bfe73648SShuo Chen{
111bfe73648SShuo Chen  Timer* timer = new Timer(cb, when, interval);
112bfe73648SShuo Chen  loop_->runInLoop(
113344a2ce1SShuo Chen      boost::bind(&TimerQueue::addTimerInLoop, this, timer));
114bfe73648SShuo Chen  return TimerId(timer);
115bfe73648SShuo Chen}
116bfe73648SShuo Chen
117344a2ce1SShuo Chenvoid TimerQueue::addTimerInLoop(Timer* timer)
118bfe73648SShuo Chen{
119bfe73648SShuo Chen  loop_->assertInLoopThread();
120bfe73648SShuo Chen  bool earliestChanged = insert(timer);
121bfe73648SShuo Chen
122bfe73648SShuo Chen  if (earliestChanged)
123bfe73648SShuo Chen  {
124bfe73648SShuo Chen    resetTimerfd(timerfd_, timer->expiration());
125bfe73648SShuo Chen  }
126bfe73648SShuo Chen}
127bfe73648SShuo Chen
128bfe73648SShuo Chenvoid TimerQueue::handleRead()
129bfe73648SShuo Chen{
130bfe73648SShuo Chen  loop_->assertInLoopThread();
131bfe73648SShuo Chen  Timestamp now(Timestamp::now());
132bfe73648SShuo Chen  readTimerfd(timerfd_, now);
133bfe73648SShuo Chen
134bfe73648SShuo Chen  std::vector<Entry> expired = getExpired(now);
135bfe73648SShuo Chen
136bfe73648SShuo Chen  // safe to callback outside critical section
137bfe73648SShuo Chen  for (std::vector<Entry>::iterator it = expired.begin();
138bfe73648SShuo Chen      it != expired.end(); ++it)
139bfe73648SShuo Chen  {
140bfe73648SShuo Chen    it->second->run();
141bfe73648SShuo Chen  }
142bfe73648SShuo Chen
143bfe73648SShuo Chen  reset(expired, now);
144bfe73648SShuo Chen}
145bfe73648SShuo Chen
146bfe73648SShuo Chenstd::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now)
147bfe73648SShuo Chen{
148bfe73648SShuo Chen  std::vector<Entry> expired;
149bfe73648SShuo Chen  Entry sentry = std::make_pair(now, reinterpret_cast<Timer*>(UINTPTR_MAX));
150bfe73648SShuo Chen  TimerList::iterator it = timers_.lower_bound(sentry);
151bfe73648SShuo Chen  assert(it == timers_.end() || now < it->first);
152bfe73648SShuo Chen  std::copy(timers_.begin(), it, back_inserter(expired));
153bfe73648SShuo Chen  timers_.erase(timers_.begin(), it);
154bfe73648SShuo Chen
155bfe73648SShuo Chen  return expired;
156bfe73648SShuo Chen}
157bfe73648SShuo Chen
158bfe73648SShuo Chenvoid TimerQueue::reset(const std::vector<Entry>& expired, Timestamp now)
159bfe73648SShuo Chen{
160bfe73648SShuo Chen  Timestamp nextExpire;
161bfe73648SShuo Chen
162bfe73648SShuo Chen  for (std::vector<Entry>::const_iterator it = expired.begin();
163bfe73648SShuo Chen      it != expired.end(); ++it)
164bfe73648SShuo Chen  {
165bfe73648SShuo Chen    if (it->second->repeat())
166bfe73648SShuo Chen    {
167bfe73648SShuo Chen      it->second->restart(now);
168bfe73648SShuo Chen      insert(it->second);
169bfe73648SShuo Chen    }
170bfe73648SShuo Chen    else
171bfe73648SShuo Chen    {
172bfe73648SShuo Chen      // FIXME move to a free list
173bfe73648SShuo Chen      delete it->second;
174bfe73648SShuo Chen    }
175bfe73648SShuo Chen  }
176bfe73648SShuo Chen
177bfe73648SShuo Chen  if (!timers_.empty())
178bfe73648SShuo Chen  {
179bfe73648SShuo Chen    nextExpire = timers_.begin()->second->expiration();
180bfe73648SShuo Chen  }
181bfe73648SShuo Chen
182bfe73648SShuo Chen  if (nextExpire.valid())
183bfe73648SShuo Chen  {
184bfe73648SShuo Chen    resetTimerfd(timerfd_, nextExpire);
185bfe73648SShuo Chen  }
186bfe73648SShuo Chen}
187bfe73648SShuo Chen
188bfe73648SShuo Chenbool TimerQueue::insert(Timer* timer)
189bfe73648SShuo Chen{
190bfe73648SShuo Chen  bool earliestChanged = false;
191bfe73648SShuo Chen  Timestamp when = timer->expiration();
192bfe73648SShuo Chen  TimerList::iterator it = timers_.begin();
193bfe73648SShuo Chen  if (it == timers_.end() || when < it->first)
194bfe73648SShuo Chen  {
195bfe73648SShuo Chen    earliestChanged = true;
196bfe73648SShuo Chen  }
197bfe73648SShuo Chen  std::pair<TimerList::iterator, bool> result =
198bfe73648SShuo Chen          timers_.insert(std::make_pair(when, timer));
199bfe73648SShuo Chen  assert(result.second);
200bfe73648SShuo Chen  return earliestChanged;
201bfe73648SShuo Chen}
202bfe73648SShuo Chen
203