TimerQueue.cc revision b4a5ce52
12745a763SShuo Chen// excerpts from http://code.google.com/p/muduo/ 22745a763SShuo Chen// 32745a763SShuo Chen// Use of this source code is governed by a BSD-style license 42745a763SShuo Chen// that can be found in the License file. 52745a763SShuo Chen// 62745a763SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com) 72745a763SShuo Chen 82745a763SShuo Chen#define __STDC_LIMIT_MACROS 92745a763SShuo Chen#include "TimerQueue.h" 102745a763SShuo Chen 112745a763SShuo Chen#include "logging/Logging.h" 122745a763SShuo Chen#include "EventLoop.h" 132745a763SShuo Chen#include "Timer.h" 142745a763SShuo Chen#include "TimerId.h" 152745a763SShuo Chen 162745a763SShuo Chen#include <boost/bind.hpp> 172745a763SShuo Chen 182745a763SShuo Chen#include <sys/timerfd.h> 192745a763SShuo Chen 202745a763SShuo Chennamespace muduo 212745a763SShuo Chen{ 222745a763SShuo Chennamespace detail 232745a763SShuo Chen{ 242745a763SShuo Chen 252745a763SShuo Chenint createTimerfd() 262745a763SShuo Chen{ 272745a763SShuo Chen int timerfd = ::timerfd_create(CLOCK_MONOTONIC, 282745a763SShuo Chen TFD_NONBLOCK | TFD_CLOEXEC); 292745a763SShuo Chen if (timerfd < 0) 302745a763SShuo Chen { 312745a763SShuo Chen LOG_SYSFATAL << "Failed in timerfd_create"; 322745a763SShuo Chen } 332745a763SShuo Chen return timerfd; 342745a763SShuo Chen} 352745a763SShuo Chen 362745a763SShuo Chenstruct timespec howMuchTimeFromNow(Timestamp when) 372745a763SShuo Chen{ 382745a763SShuo Chen int64_t microseconds = when.microSecondsSinceEpoch() 392745a763SShuo Chen - Timestamp::now().microSecondsSinceEpoch(); 402745a763SShuo Chen if (microseconds < 100) 412745a763SShuo Chen { 422745a763SShuo Chen microseconds = 100; 432745a763SShuo Chen } 442745a763SShuo Chen struct timespec ts; 452745a763SShuo Chen ts.tv_sec = static_cast<time_t>( 462745a763SShuo Chen microseconds / Timestamp::kMicroSecondsPerSecond); 472745a763SShuo Chen ts.tv_nsec = static_cast<long>( 482745a763SShuo Chen (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000); 492745a763SShuo Chen return ts; 502745a763SShuo Chen} 512745a763SShuo Chen 522745a763SShuo Chenvoid readTimerfd(int timerfd, Timestamp now) 532745a763SShuo Chen{ 542745a763SShuo Chen uint64_t howmany; 552745a763SShuo Chen ssize_t n = ::read(timerfd, &howmany, sizeof howmany); 562745a763SShuo Chen LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); 572745a763SShuo Chen if (n != sizeof howmany) 582745a763SShuo Chen { 592745a763SShuo Chen LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8"; 602745a763SShuo Chen } 612745a763SShuo Chen} 622745a763SShuo Chen 632745a763SShuo Chenvoid resetTimerfd(int timerfd, Timestamp expiration) 642745a763SShuo Chen{ 652745a763SShuo Chen // wake up loop by timerfd_settime() 662745a763SShuo Chen struct itimerspec newValue; 672745a763SShuo Chen struct itimerspec oldValue; 682745a763SShuo Chen bzero(&newValue, sizeof newValue); 692745a763SShuo Chen bzero(&oldValue, sizeof oldValue); 702745a763SShuo Chen newValue.it_value = howMuchTimeFromNow(expiration); 71b4a5ce52SShuo Chen int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue); 722745a763SShuo Chen if (ret) 732745a763SShuo Chen { 742745a763SShuo Chen LOG_SYSERR << "timerfd_settime()"; 752745a763SShuo Chen } 762745a763SShuo Chen} 772745a763SShuo Chen 782745a763SShuo Chen} 792745a763SShuo Chen} 802745a763SShuo Chen 812745a763SShuo Chenusing namespace muduo; 822745a763SShuo Chenusing namespace muduo::detail; 832745a763SShuo Chen 842745a763SShuo ChenTimerQueue::TimerQueue(EventLoop* loop) 852745a763SShuo Chen : loop_(loop), 862745a763SShuo Chen timerfd_(createTimerfd()), 872745a763SShuo Chen timerfdChannel_(loop, timerfd_), 882745a763SShuo Chen timers_() 892745a763SShuo Chen{ 902745a763SShuo Chen timerfdChannel_.setReadCallback( 912745a763SShuo Chen boost::bind(&TimerQueue::handleRead, this)); 922745a763SShuo Chen // we are always reading the timerfd, we disarm it with timerfd_settime. 932745a763SShuo Chen timerfdChannel_.enableReading(); 942745a763SShuo Chen} 952745a763SShuo Chen 962745a763SShuo ChenTimerQueue::~TimerQueue() 972745a763SShuo Chen{ 982745a763SShuo Chen ::close(timerfd_); 992745a763SShuo Chen // do not remove channel, since we're in EventLoop::dtor(); 1002745a763SShuo Chen for (TimerList::iterator it = timers_.begin(); 1012745a763SShuo Chen it != timers_.end(); ++it) 1022745a763SShuo Chen { 1032745a763SShuo Chen delete it->second; 1042745a763SShuo Chen } 1052745a763SShuo Chen} 1062745a763SShuo Chen 1072745a763SShuo ChenTimerId TimerQueue::addTimer(const TimerCallback& cb, 1082745a763SShuo Chen Timestamp when, 1092745a763SShuo Chen double interval) 1102745a763SShuo Chen{ 1112745a763SShuo Chen Timer* timer = new Timer(cb, when, interval); 1122745a763SShuo Chen loop_->runInLoop( 1132745a763SShuo Chen boost::bind(&TimerQueue::scheduleInLoop, this, timer)); 1142745a763SShuo Chen return TimerId(timer); 1152745a763SShuo Chen} 1162745a763SShuo Chen 1172745a763SShuo Chenvoid TimerQueue::scheduleInLoop(Timer* timer) 1182745a763SShuo Chen{ 1192745a763SShuo Chen loop_->assertInLoopThread(); 1202745a763SShuo Chen bool earliestChanged = insert(timer); 1212745a763SShuo Chen 1222745a763SShuo Chen if (earliestChanged) 1232745a763SShuo Chen { 1242745a763SShuo Chen resetTimerfd(timerfd_, timer->expiration()); 1252745a763SShuo Chen } 1262745a763SShuo Chen} 1272745a763SShuo Chen 1282745a763SShuo Chenvoid TimerQueue::handleRead() 1292745a763SShuo Chen{ 1302745a763SShuo Chen loop_->assertInLoopThread(); 1312745a763SShuo Chen Timestamp now(Timestamp::now()); 1322745a763SShuo Chen readTimerfd(timerfd_, now); 1332745a763SShuo Chen 1342745a763SShuo Chen std::vector<Entry> expired = getExpired(now); 1352745a763SShuo Chen 1362745a763SShuo Chen // safe to callback outside critical section 1372745a763SShuo Chen for (std::vector<Entry>::iterator it = expired.begin(); 1382745a763SShuo Chen it != expired.end(); ++it) 1392745a763SShuo Chen { 1402745a763SShuo Chen it->second->run(); 1412745a763SShuo Chen } 1422745a763SShuo Chen 1432745a763SShuo Chen reset(expired, now); 1442745a763SShuo Chen} 1452745a763SShuo Chen 1462745a763SShuo Chenstd::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now) 1472745a763SShuo Chen{ 1482745a763SShuo Chen std::vector<Entry> expired; 1492745a763SShuo Chen Entry sentry = std::make_pair(now, reinterpret_cast<Timer*>(UINTPTR_MAX)); 1502745a763SShuo Chen TimerList::iterator it = timers_.lower_bound(sentry); 1512745a763SShuo Chen assert(it == timers_.end() || now < it->first); 1522745a763SShuo Chen std::copy(timers_.begin(), it, back_inserter(expired)); 1532745a763SShuo Chen timers_.erase(timers_.begin(), it); 1542745a763SShuo Chen 1552745a763SShuo Chen return expired; 1562745a763SShuo Chen} 1572745a763SShuo Chen 1582745a763SShuo Chenvoid TimerQueue::reset(const std::vector<Entry>& expired, Timestamp now) 1592745a763SShuo Chen{ 1602745a763SShuo Chen Timestamp nextExpire; 1612745a763SShuo Chen 1622745a763SShuo Chen for (std::vector<Entry>::const_iterator it = expired.begin(); 1632745a763SShuo Chen it != expired.end(); ++it) 1642745a763SShuo Chen { 1652745a763SShuo Chen if (it->second->repeat()) 1662745a763SShuo Chen { 1672745a763SShuo Chen it->second->restart(now); 1682745a763SShuo Chen insert(it->second); 1692745a763SShuo Chen } 1702745a763SShuo Chen else 1712745a763SShuo Chen { 1722745a763SShuo Chen // FIXME move to a free list 1732745a763SShuo Chen delete it->second; 1742745a763SShuo Chen } 1752745a763SShuo Chen } 1762745a763SShuo Chen 1772745a763SShuo Chen if (!timers_.empty()) 1782745a763SShuo Chen { 1792745a763SShuo Chen nextExpire = timers_.begin()->second->expiration(); 1802745a763SShuo Chen } 1812745a763SShuo Chen 1822745a763SShuo Chen if (nextExpire.valid()) 1832745a763SShuo Chen { 1842745a763SShuo Chen resetTimerfd(timerfd_, nextExpire); 1852745a763SShuo Chen } 1862745a763SShuo Chen} 1872745a763SShuo Chen 1882745a763SShuo Chenbool TimerQueue::insert(Timer* timer) 1892745a763SShuo Chen{ 1902745a763SShuo Chen bool earliestChanged = false; 1912745a763SShuo Chen Timestamp when = timer->expiration(); 1922745a763SShuo Chen TimerList::iterator it = timers_.begin(); 1932745a763SShuo Chen if (it == timers_.end() || when < it->first) 1942745a763SShuo Chen { 1952745a763SShuo Chen earliestChanged = true; 1962745a763SShuo Chen } 197a20e676dSShuo Chen std::pair<TimerList::iterator, bool> result = 198a20e676dSShuo Chen timers_.insert(std::make_pair(when, timer)); 1992745a763SShuo Chen assert(result.second); 2002745a763SShuo Chen return earliestChanged; 2012745a763SShuo Chen} 2022745a763SShuo Chen 203