TimerQueue.cc revision b4a5ce52
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( 113bfe73648SShuo Chen boost::bind(&TimerQueue::scheduleInLoop, this, timer)); 114bfe73648SShuo Chen return TimerId(timer); 115bfe73648SShuo Chen} 116bfe73648SShuo Chen 117bfe73648SShuo Chenvoid TimerQueue::scheduleInLoop(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