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