1566406ccSShuo Chen // excerpts from http://code.google.com/p/muduo/
2566406ccSShuo Chen //
3566406ccSShuo Chen // Use of this source code is governed by a BSD-style license
4566406ccSShuo Chen // that can be found in the License file.
5566406ccSShuo Chen //
6566406ccSShuo Chen // Author: Shuo Chen (chenshuo at chenshuo dot com)
7566406ccSShuo Chen 
8566406ccSShuo Chen #define __STDC_LIMIT_MACROS
9566406ccSShuo Chen #include "TimerQueue.h"
10566406ccSShuo Chen 
11566406ccSShuo Chen #include "logging/Logging.h"
12566406ccSShuo Chen #include "EventLoop.h"
13566406ccSShuo Chen #include "Timer.h"
14566406ccSShuo Chen #include "TimerId.h"
15566406ccSShuo Chen 
16566406ccSShuo Chen #include <boost/bind.hpp>
17566406ccSShuo Chen 
18566406ccSShuo Chen #include <sys/timerfd.h>
19566406ccSShuo Chen 
20566406ccSShuo Chen namespace muduo
21566406ccSShuo Chen {
22566406ccSShuo Chen namespace detail
23566406ccSShuo Chen {
24566406ccSShuo Chen 
25566406ccSShuo Chen int createTimerfd()
26566406ccSShuo Chen {
27566406ccSShuo Chen   int timerfd = ::timerfd_create(CLOCK_MONOTONIC,
28566406ccSShuo Chen                                  TFD_NONBLOCK | TFD_CLOEXEC);
29566406ccSShuo Chen   if (timerfd < 0)
30566406ccSShuo Chen   {
31566406ccSShuo Chen     LOG_SYSFATAL << "Failed in timerfd_create";
32566406ccSShuo Chen   }
33566406ccSShuo Chen   return timerfd;
34566406ccSShuo Chen }
35566406ccSShuo Chen 
36566406ccSShuo Chen struct timespec howMuchTimeFromNow(Timestamp when)
37566406ccSShuo Chen {
38566406ccSShuo Chen   int64_t microseconds = when.microSecondsSinceEpoch()
39566406ccSShuo Chen                          - Timestamp::now().microSecondsSinceEpoch();
40566406ccSShuo Chen   if (microseconds < 100)
41566406ccSShuo Chen   {
42566406ccSShuo Chen     microseconds = 100;
43566406ccSShuo Chen   }
44566406ccSShuo Chen   struct timespec ts;
45566406ccSShuo Chen   ts.tv_sec = static_cast<time_t>(
46566406ccSShuo Chen       microseconds / Timestamp::kMicroSecondsPerSecond);
47566406ccSShuo Chen   ts.tv_nsec = static_cast<long>(
48566406ccSShuo Chen       (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000);
49566406ccSShuo Chen   return ts;
50566406ccSShuo Chen }
51566406ccSShuo Chen 
52566406ccSShuo Chen void readTimerfd(int timerfd, Timestamp now)
53566406ccSShuo Chen {
54566406ccSShuo Chen   uint64_t howmany;
55566406ccSShuo Chen   ssize_t n = ::read(timerfd, &howmany, sizeof howmany);
56566406ccSShuo Chen   LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString();
57566406ccSShuo Chen   if (n != sizeof howmany)
58566406ccSShuo Chen   {
59566406ccSShuo Chen     LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8";
60566406ccSShuo Chen   }
61566406ccSShuo Chen }
62566406ccSShuo Chen 
63566406ccSShuo Chen void resetTimerfd(int timerfd, Timestamp expiration)
64566406ccSShuo Chen {
65566406ccSShuo Chen   // wake up loop by timerfd_settime()
66566406ccSShuo Chen   struct itimerspec newValue;
67566406ccSShuo Chen   struct itimerspec oldValue;
68566406ccSShuo Chen   bzero(&newValue, sizeof newValue);
69566406ccSShuo Chen   bzero(&oldValue, sizeof oldValue);
70566406ccSShuo Chen   newValue.it_value = howMuchTimeFromNow(expiration);
71b4a5ce52SShuo Chen   int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue);
72566406ccSShuo Chen   if (ret)
73566406ccSShuo Chen   {
74566406ccSShuo Chen     LOG_SYSERR << "timerfd_settime()";
75566406ccSShuo Chen   }
76566406ccSShuo Chen }
77566406ccSShuo Chen 
78566406ccSShuo Chen }
79566406ccSShuo Chen }
80566406ccSShuo Chen 
81566406ccSShuo Chen using namespace muduo;
82566406ccSShuo Chen using namespace muduo::detail;
83566406ccSShuo Chen 
84566406ccSShuo Chen TimerQueue::TimerQueue(EventLoop* loop)
85566406ccSShuo Chen   : loop_(loop),
86566406ccSShuo Chen     timerfd_(createTimerfd()),
87566406ccSShuo Chen     timerfdChannel_(loop, timerfd_),
88566406ccSShuo Chen     timers_()
89566406ccSShuo Chen {
90566406ccSShuo Chen   timerfdChannel_.setReadCallback(
91566406ccSShuo Chen       boost::bind(&TimerQueue::handleRead, this));
92566406ccSShuo Chen   // we are always reading the timerfd, we disarm it with timerfd_settime.
93566406ccSShuo Chen   timerfdChannel_.enableReading();
94566406ccSShuo Chen }
95566406ccSShuo Chen 
96566406ccSShuo Chen TimerQueue::~TimerQueue()
97566406ccSShuo Chen {
98566406ccSShuo Chen   ::close(timerfd_);
99566406ccSShuo Chen   // do not remove channel, since we're in EventLoop::dtor();
100566406ccSShuo Chen   for (TimerList::iterator it = timers_.begin();
101566406ccSShuo Chen       it != timers_.end(); ++it)
102566406ccSShuo Chen   {
103566406ccSShuo Chen     delete it->second;
104566406ccSShuo Chen   }
105566406ccSShuo Chen }
106566406ccSShuo Chen 
107566406ccSShuo Chen TimerId TimerQueue::addTimer(const TimerCallback& cb,
108566406ccSShuo Chen                              Timestamp when,
109566406ccSShuo Chen                              double interval)
110566406ccSShuo Chen {
111566406ccSShuo Chen   Timer* timer = new Timer(cb, when, interval);
112566406ccSShuo Chen+  loop_->runInLoop(
113344a2ce1SShuo Chen+      boost::bind(&TimerQueue::addTimerInLoop, this, timer));
114566406ccSShuo Chen+  return TimerId(timer);
1150dd528a5SShuo Chen+}
116b4a5ce52SShuo Chen 
117344a2ce1SShuo Chen+void TimerQueue::addTimerInLoop(Timer* timer)
118566406ccSShuo Chen+{
119566406ccSShuo Chen   loop_->assertInLoopThread();
120566406ccSShuo Chen   bool earliestChanged = insert(timer);
121566406ccSShuo Chen 
122566406ccSShuo Chen   if (earliestChanged)
123566406ccSShuo Chen   {
124566406ccSShuo Chen     resetTimerfd(timerfd_, timer->expiration());
125566406ccSShuo Chen   }
126566406ccSShuo Chen-  return TimerId(timer);
1270dd528a5SShuo Chen }
128566406ccSShuo Chen 
129566406ccSShuo Chen void TimerQueue::handleRead()
130566406ccSShuo Chen {
131566406ccSShuo Chen   loop_->assertInLoopThread();
132566406ccSShuo Chen   Timestamp now(Timestamp::now());
133566406ccSShuo Chen   readTimerfd(timerfd_, now);
134566406ccSShuo Chen 
135566406ccSShuo Chen   std::vector<Entry> expired = getExpired(now);
136566406ccSShuo Chen 
137566406ccSShuo Chen   // safe to callback outside critical section
138566406ccSShuo Chen   for (std::vector<Entry>::iterator it = expired.begin();
139566406ccSShuo Chen       it != expired.end(); ++it)
140566406ccSShuo Chen   {
141566406ccSShuo Chen     it->second->run();
142566406ccSShuo Chen   }
143566406ccSShuo Chen 
144566406ccSShuo Chen   reset(expired, now);
145566406ccSShuo Chen }
146566406ccSShuo Chen 
147566406ccSShuo Chen std::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now)
148566406ccSShuo Chen {
149566406ccSShuo Chen   std::vector<Entry> expired;
150566406ccSShuo Chen   Entry sentry = std::make_pair(now, reinterpret_cast<Timer*>(UINTPTR_MAX));
151566406ccSShuo Chen   TimerList::iterator it = timers_.lower_bound(sentry);
152566406ccSShuo Chen   assert(it == timers_.end() || now < it->first);
153566406ccSShuo Chen   std::copy(timers_.begin(), it, back_inserter(expired));
154566406ccSShuo Chen   timers_.erase(timers_.begin(), it);
155566406ccSShuo Chen 
156566406ccSShuo Chen   return expired;
157566406ccSShuo Chen }
158566406ccSShuo Chen 
159566406ccSShuo Chen void TimerQueue::reset(const std::vector<Entry>& expired, Timestamp now)
160566406ccSShuo Chen {
161566406ccSShuo Chen   Timestamp nextExpire;
162566406ccSShuo Chen 
163566406ccSShuo Chen   for (std::vector<Entry>::const_iterator it = expired.begin();
164566406ccSShuo Chen       it != expired.end(); ++it)
165566406ccSShuo Chen   {
166566406ccSShuo Chen     if (it->second->repeat())
167566406ccSShuo Chen     {
168566406ccSShuo Chen       it->second->restart(now);
169566406ccSShuo Chen       insert(it->second);
170566406ccSShuo Chen     }
171566406ccSShuo Chen     else
172566406ccSShuo Chen     {
173566406ccSShuo Chen       // FIXME move to a free list
174566406ccSShuo Chen       delete it->second;
175566406ccSShuo Chen     }
176566406ccSShuo Chen   }
177566406ccSShuo Chen 
178566406ccSShuo Chen   if (!timers_.empty())
179566406ccSShuo Chen   {
180566406ccSShuo Chen     nextExpire = timers_.begin()->second->expiration();
181566406ccSShuo Chen   }
182566406ccSShuo Chen 
183566406ccSShuo Chen   if (nextExpire.valid())
184566406ccSShuo Chen   {
185566406ccSShuo Chen     resetTimerfd(timerfd_, nextExpire);
186566406ccSShuo Chen   }
187566406ccSShuo Chen }
188566406ccSShuo Chen 
189566406ccSShuo Chen bool TimerQueue::insert(Timer* timer)
190566406ccSShuo Chen {
191566406ccSShuo Chen   bool earliestChanged = false;
192566406ccSShuo Chen   Timestamp when = timer->expiration();
193566406ccSShuo Chen   TimerList::iterator it = timers_.begin();
194566406ccSShuo Chen   if (it == timers_.end() || when < it->first)
195566406ccSShuo Chen   {
196566406ccSShuo Chen     earliestChanged = true;
197566406ccSShuo Chen   }
198048f6023SShuo Chen   std::pair<TimerList::iterator, bool> result =
199048f6023SShuo Chen           timers_.insert(std::make_pair(when, timer));
200566406ccSShuo Chen   assert(result.second);
201566406ccSShuo Chen   return earliestChanged;
202566406ccSShuo Chen }
203566406ccSShuo Chen 
204