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