165c497a3SShuo Chen// excerpts from http://code.google.com/p/muduo/ 265c497a3SShuo Chen// 365c497a3SShuo Chen// Use of this source code is governed by a BSD-style license 465c497a3SShuo Chen// that can be found in the License file. 565c497a3SShuo Chen// 665c497a3SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com) 765c497a3SShuo Chen 865c497a3SShuo Chen#define __STDC_LIMIT_MACROS 965c497a3SShuo Chen#include "TimerQueue.h" 1065c497a3SShuo Chen 1165c497a3SShuo Chen#include "logging/Logging.h" 1265c497a3SShuo Chen#include "EventLoop.h" 1365c497a3SShuo Chen#include "Timer.h" 1465c497a3SShuo Chen#include "TimerId.h" 1565c497a3SShuo Chen 1665c497a3SShuo Chen#include <boost/bind.hpp> 1765c497a3SShuo Chen 1865c497a3SShuo Chen#include <sys/timerfd.h> 1965c497a3SShuo Chen 2065c497a3SShuo Chennamespace muduo 2165c497a3SShuo Chen{ 2265c497a3SShuo Chennamespace detail 2365c497a3SShuo Chen{ 2465c497a3SShuo Chen 2565c497a3SShuo Chenint createTimerfd() 2665c497a3SShuo Chen{ 2765c497a3SShuo Chen int timerfd = ::timerfd_create(CLOCK_MONOTONIC, 2865c497a3SShuo Chen TFD_NONBLOCK | TFD_CLOEXEC); 2965c497a3SShuo Chen if (timerfd < 0) 3065c497a3SShuo Chen { 3165c497a3SShuo Chen LOG_SYSFATAL << "Failed in timerfd_create"; 3265c497a3SShuo Chen } 3365c497a3SShuo Chen return timerfd; 3465c497a3SShuo Chen} 3565c497a3SShuo Chen 3665c497a3SShuo Chenstruct timespec howMuchTimeFromNow(Timestamp when) 3765c497a3SShuo Chen{ 3865c497a3SShuo Chen int64_t microseconds = when.microSecondsSinceEpoch() 3965c497a3SShuo Chen - Timestamp::now().microSecondsSinceEpoch(); 4065c497a3SShuo Chen if (microseconds < 100) 4165c497a3SShuo Chen { 4265c497a3SShuo Chen microseconds = 100; 4365c497a3SShuo Chen } 4465c497a3SShuo Chen struct timespec ts; 4565c497a3SShuo Chen ts.tv_sec = static_cast<time_t>( 4665c497a3SShuo Chen microseconds / Timestamp::kMicroSecondsPerSecond); 4765c497a3SShuo Chen ts.tv_nsec = static_cast<long>( 4865c497a3SShuo Chen (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000); 4965c497a3SShuo Chen return ts; 5065c497a3SShuo Chen} 5165c497a3SShuo Chen 5265c497a3SShuo Chenvoid readTimerfd(int timerfd, Timestamp now) 5365c497a3SShuo Chen{ 5465c497a3SShuo Chen uint64_t howmany; 5565c497a3SShuo Chen ssize_t n = ::read(timerfd, &howmany, sizeof howmany); 5665c497a3SShuo Chen LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); 5765c497a3SShuo Chen if (n != sizeof howmany) 5865c497a3SShuo Chen { 5965c497a3SShuo Chen LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8"; 6065c497a3SShuo Chen } 6165c497a3SShuo Chen} 6265c497a3SShuo Chen 6365c497a3SShuo Chenvoid resetTimerfd(int timerfd, Timestamp expiration) 6465c497a3SShuo Chen{ 6565c497a3SShuo Chen // wake up loop by timerfd_settime() 6665c497a3SShuo Chen struct itimerspec newValue; 6765c497a3SShuo Chen struct itimerspec oldValue; 6865c497a3SShuo Chen bzero(&newValue, sizeof newValue); 6965c497a3SShuo Chen bzero(&oldValue, sizeof oldValue); 7065c497a3SShuo Chen newValue.it_value = howMuchTimeFromNow(expiration); 71b4a5ce52SShuo Chen int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue); 7265c497a3SShuo Chen if (ret) 7365c497a3SShuo Chen { 7465c497a3SShuo Chen LOG_SYSERR << "timerfd_settime()"; 7565c497a3SShuo Chen } 7665c497a3SShuo Chen} 7765c497a3SShuo Chen 7865c497a3SShuo Chen} 7965c497a3SShuo Chen} 8065c497a3SShuo Chen 8165c497a3SShuo Chenusing namespace muduo; 8265c497a3SShuo Chenusing namespace muduo::detail; 8365c497a3SShuo Chen 8465c497a3SShuo ChenTimerQueue::TimerQueue(EventLoop* loop) 8565c497a3SShuo Chen : loop_(loop), 8665c497a3SShuo Chen timerfd_(createTimerfd()), 8765c497a3SShuo Chen timerfdChannel_(loop, timerfd_), 8865c497a3SShuo Chen timers_() 8965c497a3SShuo Chen{ 9065c497a3SShuo Chen timerfdChannel_.setReadCallback( 9165c497a3SShuo Chen boost::bind(&TimerQueue::handleRead, this)); 9265c497a3SShuo Chen // we are always reading the timerfd, we disarm it with timerfd_settime. 9365c497a3SShuo Chen timerfdChannel_.enableReading(); 9465c497a3SShuo Chen} 9565c497a3SShuo Chen 9665c497a3SShuo ChenTimerQueue::~TimerQueue() 9765c497a3SShuo Chen{ 9865c497a3SShuo Chen ::close(timerfd_); 9965c497a3SShuo Chen // do not remove channel, since we're in EventLoop::dtor(); 10065c497a3SShuo Chen for (TimerList::iterator it = timers_.begin(); 10165c497a3SShuo Chen it != timers_.end(); ++it) 10265c497a3SShuo Chen { 10365c497a3SShuo Chen delete it->second; 10465c497a3SShuo Chen } 10565c497a3SShuo Chen} 10665c497a3SShuo Chen 10765c497a3SShuo ChenTimerId TimerQueue::addTimer(const TimerCallback& cb, 10865c497a3SShuo Chen Timestamp when, 10965c497a3SShuo Chen double interval) 11065c497a3SShuo Chen{ 11165c497a3SShuo Chen Timer* timer = new Timer(cb, when, interval); 11265c497a3SShuo Chen loop_->runInLoop( 113344a2ce1SShuo Chen boost::bind(&TimerQueue::addTimerInLoop, this, timer)); 11465c497a3SShuo Chen return TimerId(timer); 11565c497a3SShuo Chen} 11665c497a3SShuo Chen 117344a2ce1SShuo Chenvoid TimerQueue::addTimerInLoop(Timer* timer) 11865c497a3SShuo Chen{ 11965c497a3SShuo Chen loop_->assertInLoopThread(); 12065c497a3SShuo Chen bool earliestChanged = insert(timer); 12165c497a3SShuo Chen 12265c497a3SShuo Chen if (earliestChanged) 12365c497a3SShuo Chen { 12465c497a3SShuo Chen resetTimerfd(timerfd_, timer->expiration()); 12565c497a3SShuo Chen } 12665c497a3SShuo Chen} 12765c497a3SShuo Chen 12865c497a3SShuo Chenvoid TimerQueue::handleRead() 12965c497a3SShuo Chen{ 13065c497a3SShuo Chen loop_->assertInLoopThread(); 13165c497a3SShuo Chen Timestamp now(Timestamp::now()); 13265c497a3SShuo Chen readTimerfd(timerfd_, now); 13365c497a3SShuo Chen 13465c497a3SShuo Chen std::vector<Entry> expired = getExpired(now); 13565c497a3SShuo Chen 13665c497a3SShuo Chen // safe to callback outside critical section 13765c497a3SShuo Chen for (std::vector<Entry>::iterator it = expired.begin(); 13865c497a3SShuo Chen it != expired.end(); ++it) 13965c497a3SShuo Chen { 14065c497a3SShuo Chen it->second->run(); 14165c497a3SShuo Chen } 14265c497a3SShuo Chen 14365c497a3SShuo Chen reset(expired, now); 14465c497a3SShuo Chen} 14565c497a3SShuo Chen 14665c497a3SShuo Chenstd::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now) 14765c497a3SShuo Chen{ 14865c497a3SShuo Chen std::vector<Entry> expired; 14965c497a3SShuo Chen Entry sentry = std::make_pair(now, reinterpret_cast<Timer*>(UINTPTR_MAX)); 15065c497a3SShuo Chen TimerList::iterator it = timers_.lower_bound(sentry); 15165c497a3SShuo Chen assert(it == timers_.end() || now < it->first); 15265c497a3SShuo Chen std::copy(timers_.begin(), it, back_inserter(expired)); 15365c497a3SShuo Chen timers_.erase(timers_.begin(), it); 15465c497a3SShuo Chen 15565c497a3SShuo Chen return expired; 15665c497a3SShuo Chen} 15765c497a3SShuo Chen 15865c497a3SShuo Chenvoid TimerQueue::reset(const std::vector<Entry>& expired, Timestamp now) 15965c497a3SShuo Chen{ 16065c497a3SShuo Chen Timestamp nextExpire; 16165c497a3SShuo Chen 16265c497a3SShuo Chen for (std::vector<Entry>::const_iterator it = expired.begin(); 16365c497a3SShuo Chen it != expired.end(); ++it) 16465c497a3SShuo Chen { 16565c497a3SShuo Chen if (it->second->repeat()) 16665c497a3SShuo Chen { 16765c497a3SShuo Chen it->second->restart(now); 16865c497a3SShuo Chen insert(it->second); 16965c497a3SShuo Chen } 17065c497a3SShuo Chen else 17165c497a3SShuo Chen { 17265c497a3SShuo Chen // FIXME move to a free list 17365c497a3SShuo Chen delete it->second; 17465c497a3SShuo Chen } 17565c497a3SShuo Chen } 17665c497a3SShuo Chen 17765c497a3SShuo Chen if (!timers_.empty()) 17865c497a3SShuo Chen { 17965c497a3SShuo Chen nextExpire = timers_.begin()->second->expiration(); 18065c497a3SShuo Chen } 18165c497a3SShuo Chen 18265c497a3SShuo Chen if (nextExpire.valid()) 18365c497a3SShuo Chen { 18465c497a3SShuo Chen resetTimerfd(timerfd_, nextExpire); 18565c497a3SShuo Chen } 18665c497a3SShuo Chen} 18765c497a3SShuo Chen 18865c497a3SShuo Chenbool TimerQueue::insert(Timer* timer) 18965c497a3SShuo Chen{ 19065c497a3SShuo Chen bool earliestChanged = false; 19165c497a3SShuo Chen Timestamp when = timer->expiration(); 19265c497a3SShuo Chen TimerList::iterator it = timers_.begin(); 19365c497a3SShuo Chen if (it == timers_.end() || when < it->first) 19465c497a3SShuo Chen { 19565c497a3SShuo Chen earliestChanged = true; 19665c497a3SShuo Chen } 19765c497a3SShuo Chen std::pair<TimerList::iterator, bool> result = 19865c497a3SShuo Chen timers_.insert(std::make_pair(when, timer)); 19965c497a3SShuo Chen assert(result.second); 20065c497a3SShuo Chen return earliestChanged; 20165c497a3SShuo Chen} 20265c497a3SShuo Chen 203