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