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