TimerQueue.cc revision 40161064
140161064SShuo Chen// excerpts from http://code.google.com/p/muduo/ 240161064SShuo Chen// 340161064SShuo Chen// Use of this source code is governed by a BSD-style license 440161064SShuo Chen// that can be found in the License file. 540161064SShuo Chen// 640161064SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com) 740161064SShuo Chen 840161064SShuo Chen#define __STDC_LIMIT_MACROS 940161064SShuo Chen#include "TimerQueue.h" 1040161064SShuo Chen 1140161064SShuo Chen#include "logging/Logging.h" 1240161064SShuo Chen#include "EventLoop.h" 1340161064SShuo Chen#include "Timer.h" 1440161064SShuo Chen#include "TimerId.h" 1540161064SShuo Chen 1640161064SShuo Chen#include <boost/bind.hpp> 1740161064SShuo Chen 1840161064SShuo Chen#include <sys/timerfd.h> 1940161064SShuo Chen 2040161064SShuo Chennamespace muduo 2140161064SShuo Chen{ 2240161064SShuo Chennamespace detail 2340161064SShuo Chen{ 2440161064SShuo Chen 2540161064SShuo Chenint createTimerfd() 2640161064SShuo Chen{ 2740161064SShuo Chen int timerfd = ::timerfd_create(CLOCK_MONOTONIC, 2840161064SShuo Chen TFD_NONBLOCK | TFD_CLOEXEC); 2940161064SShuo Chen if (timerfd < 0) 3040161064SShuo Chen { 3140161064SShuo Chen LOG_SYSFATAL << "Failed in timerfd_create"; 3240161064SShuo Chen } 3340161064SShuo Chen return timerfd; 3440161064SShuo Chen} 3540161064SShuo Chen 3640161064SShuo Chenstruct timespec howMuchTimeFromNow(Timestamp when) 3740161064SShuo Chen{ 3840161064SShuo Chen int64_t microseconds = when.microSecondsSinceEpoch() 3940161064SShuo Chen - Timestamp::now().microSecondsSinceEpoch(); 4040161064SShuo Chen if (microseconds < 100) 4140161064SShuo Chen { 4240161064SShuo Chen microseconds = 100; 4340161064SShuo Chen } 4440161064SShuo Chen struct timespec ts; 4540161064SShuo Chen ts.tv_sec = static_cast<time_t>( 4640161064SShuo Chen microseconds / Timestamp::kMicroSecondsPerSecond); 4740161064SShuo Chen ts.tv_nsec = static_cast<long>( 4840161064SShuo Chen (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000); 4940161064SShuo Chen return ts; 5040161064SShuo Chen} 5140161064SShuo Chen 5240161064SShuo Chenvoid readTimerfd(int timerfd, Timestamp now) 5340161064SShuo Chen{ 5440161064SShuo Chen uint64_t howmany; 5540161064SShuo Chen ssize_t n = ::read(timerfd, &howmany, sizeof howmany); 5640161064SShuo Chen LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); 5740161064SShuo Chen if (n != sizeof howmany) 5840161064SShuo Chen { 5940161064SShuo Chen LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8"; 6040161064SShuo Chen } 6140161064SShuo Chen} 6240161064SShuo Chen 6340161064SShuo Chenvoid resetTimerfd(int timerfd, Timestamp expiration) 6440161064SShuo Chen{ 6540161064SShuo Chen // wake up loop by timerfd_settime() 6640161064SShuo Chen struct itimerspec newValue; 6740161064SShuo Chen struct itimerspec oldValue; 6840161064SShuo Chen bzero(&newValue, sizeof newValue); 6940161064SShuo Chen bzero(&oldValue, sizeof oldValue); 7040161064SShuo Chen newValue.it_value = howMuchTimeFromNow(expiration); 7140161064SShuo Chen int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue); 7240161064SShuo Chen if (ret) 7340161064SShuo Chen { 7440161064SShuo Chen LOG_SYSERR << "timerfd_settime()"; 7540161064SShuo Chen } 7640161064SShuo Chen} 7740161064SShuo Chen 7840161064SShuo Chen} 7940161064SShuo Chen} 8040161064SShuo Chen 8140161064SShuo Chenusing namespace muduo; 8240161064SShuo Chenusing namespace muduo::detail; 8340161064SShuo Chen 8440161064SShuo ChenTimerQueue::TimerQueue(EventLoop* loop) 8540161064SShuo Chen : loop_(loop), 8640161064SShuo Chen timerfd_(createTimerfd()), 8740161064SShuo Chen timerfdChannel_(loop, timerfd_), 8840161064SShuo Chen timers_() 8940161064SShuo Chen{ 9040161064SShuo Chen timerfdChannel_.setReadCallback( 9140161064SShuo Chen boost::bind(&TimerQueue::handleRead, this)); 9240161064SShuo Chen // we are always reading the timerfd, we disarm it with timerfd_settime. 9340161064SShuo Chen timerfdChannel_.enableReading(); 9440161064SShuo Chen} 9540161064SShuo Chen 9640161064SShuo ChenTimerQueue::~TimerQueue() 9740161064SShuo Chen{ 9840161064SShuo Chen ::close(timerfd_); 9940161064SShuo Chen // do not remove channel, since we're in EventLoop::dtor(); 10040161064SShuo Chen for (TimerList::iterator it = timers_.begin(); 10140161064SShuo Chen it != timers_.end(); ++it) 10240161064SShuo Chen { 10340161064SShuo Chen delete it->second; 10440161064SShuo Chen } 10540161064SShuo Chen} 10640161064SShuo Chen 10740161064SShuo ChenTimerId TimerQueue::addTimer(const TimerCallback& cb, 10840161064SShuo Chen Timestamp when, 10940161064SShuo Chen double interval) 11040161064SShuo Chen{ 11140161064SShuo Chen Timer* timer = new Timer(cb, when, interval); 11240161064SShuo Chen loop_->runInLoop( 11340161064SShuo Chen boost::bind(&TimerQueue::scheduleInLoop, this, timer)); 11440161064SShuo Chen return TimerId(timer); 11540161064SShuo Chen} 11640161064SShuo Chen 11740161064SShuo Chenvoid TimerQueue::scheduleInLoop(Timer* timer) 11840161064SShuo Chen{ 11940161064SShuo Chen loop_->assertInLoopThread(); 12040161064SShuo Chen bool earliestChanged = insert(timer); 12140161064SShuo Chen 12240161064SShuo Chen if (earliestChanged) 12340161064SShuo Chen { 12440161064SShuo Chen resetTimerfd(timerfd_, timer->expiration()); 12540161064SShuo Chen } 12640161064SShuo Chen} 12740161064SShuo Chen 12840161064SShuo Chenvoid TimerQueue::handleRead() 12940161064SShuo Chen{ 13040161064SShuo Chen loop_->assertInLoopThread(); 13140161064SShuo Chen Timestamp now(Timestamp::now()); 13240161064SShuo Chen readTimerfd(timerfd_, now); 13340161064SShuo Chen 13440161064SShuo Chen std::vector<Entry> expired = getExpired(now); 13540161064SShuo Chen 13640161064SShuo Chen // safe to callback outside critical section 13740161064SShuo Chen for (std::vector<Entry>::iterator it = expired.begin(); 13840161064SShuo Chen it != expired.end(); ++it) 13940161064SShuo Chen { 14040161064SShuo Chen it->second->run(); 14140161064SShuo Chen } 14240161064SShuo Chen 14340161064SShuo Chen reset(expired, now); 14440161064SShuo Chen} 14540161064SShuo Chen 14640161064SShuo Chenstd::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now) 14740161064SShuo Chen{ 14840161064SShuo Chen std::vector<Entry> expired; 14940161064SShuo Chen Entry sentry = std::make_pair(now, reinterpret_cast<Timer*>(UINTPTR_MAX)); 15040161064SShuo Chen TimerList::iterator it = timers_.lower_bound(sentry); 15140161064SShuo Chen assert(it == timers_.end() || now < it->first); 15240161064SShuo Chen std::copy(timers_.begin(), it, back_inserter(expired)); 15340161064SShuo Chen timers_.erase(timers_.begin(), it); 15440161064SShuo Chen 15540161064SShuo Chen return expired; 15640161064SShuo Chen} 15740161064SShuo Chen 15840161064SShuo Chenvoid TimerQueue::reset(const std::vector<Entry>& expired, Timestamp now) 15940161064SShuo Chen{ 16040161064SShuo Chen Timestamp nextExpire; 16140161064SShuo Chen 16240161064SShuo Chen for (std::vector<Entry>::const_iterator it = expired.begin(); 16340161064SShuo Chen it != expired.end(); ++it) 16440161064SShuo Chen { 16540161064SShuo Chen if (it->second->repeat()) 16640161064SShuo Chen { 16740161064SShuo Chen it->second->restart(now); 16840161064SShuo Chen insert(it->second); 16940161064SShuo Chen } 17040161064SShuo Chen else 17140161064SShuo Chen { 17240161064SShuo Chen // FIXME move to a free list 17340161064SShuo Chen delete it->second; 17440161064SShuo Chen } 17540161064SShuo Chen } 17640161064SShuo Chen 17740161064SShuo Chen if (!timers_.empty()) 17840161064SShuo Chen { 17940161064SShuo Chen nextExpire = timers_.begin()->second->expiration(); 18040161064SShuo Chen } 18140161064SShuo Chen 18240161064SShuo Chen if (nextExpire.valid()) 18340161064SShuo Chen { 18440161064SShuo Chen resetTimerfd(timerfd_, nextExpire); 18540161064SShuo Chen } 18640161064SShuo Chen} 18740161064SShuo Chen 18840161064SShuo Chenbool TimerQueue::insert(Timer* timer) 18940161064SShuo Chen{ 19040161064SShuo Chen bool earliestChanged = false; 19140161064SShuo Chen Timestamp when = timer->expiration(); 19240161064SShuo Chen TimerList::iterator it = timers_.begin(); 19340161064SShuo Chen if (it == timers_.end() || when < it->first) 19440161064SShuo Chen { 19540161064SShuo Chen earliestChanged = true; 19640161064SShuo Chen } 19740161064SShuo Chen std::pair<TimerList::iterator, bool> result = 19840161064SShuo Chen timers_.insert(std::make_pair(when, timer)); 19940161064SShuo Chen assert(result.second); 20040161064SShuo Chen return earliestChanged; 20140161064SShuo Chen} 20240161064SShuo Chen 203