TimerQueue.cc revision 42bf2220
142bf2220SShuo Chen// excerpts from http://code.google.com/p/muduo/ 242bf2220SShuo Chen// 342bf2220SShuo Chen// Use of this source code is governed by a BSD-style license 442bf2220SShuo Chen// that can be found in the License file. 542bf2220SShuo Chen// 642bf2220SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com) 742bf2220SShuo Chen 842bf2220SShuo Chen#define __STDC_LIMIT_MACROS 942bf2220SShuo Chen#include "TimerQueue.h" 1042bf2220SShuo Chen 1142bf2220SShuo Chen#include "logging/Logging.h" 1242bf2220SShuo Chen#include "EventLoop.h" 1342bf2220SShuo Chen#include "Timer.h" 1442bf2220SShuo Chen#include "TimerId.h" 1542bf2220SShuo Chen 1642bf2220SShuo Chen#include <boost/bind.hpp> 1742bf2220SShuo Chen 1842bf2220SShuo Chen#include <sys/timerfd.h> 1942bf2220SShuo Chen 2042bf2220SShuo Chennamespace muduo 2142bf2220SShuo Chen{ 2242bf2220SShuo Chennamespace detail 2342bf2220SShuo Chen{ 2442bf2220SShuo Chen 2542bf2220SShuo Chenint createTimerfd() 2642bf2220SShuo Chen{ 2742bf2220SShuo Chen int timerfd = ::timerfd_create(CLOCK_MONOTONIC, 2842bf2220SShuo Chen TFD_NONBLOCK | TFD_CLOEXEC); 2942bf2220SShuo Chen if (timerfd < 0) 3042bf2220SShuo Chen { 3142bf2220SShuo Chen LOG_SYSFATAL << "Failed in timerfd_create"; 3242bf2220SShuo Chen } 3342bf2220SShuo Chen return timerfd; 3442bf2220SShuo Chen} 3542bf2220SShuo Chen 3642bf2220SShuo Chenstruct timespec howMuchTimeFromNow(Timestamp when) 3742bf2220SShuo Chen{ 3842bf2220SShuo Chen int64_t microseconds = when.microSecondsSinceEpoch() 3942bf2220SShuo Chen - Timestamp::now().microSecondsSinceEpoch(); 4042bf2220SShuo Chen if (microseconds < 100) 4142bf2220SShuo Chen { 4242bf2220SShuo Chen microseconds = 100; 4342bf2220SShuo Chen } 4442bf2220SShuo Chen struct timespec ts; 4542bf2220SShuo Chen ts.tv_sec = static_cast<time_t>( 4642bf2220SShuo Chen microseconds / Timestamp::kMicroSecondsPerSecond); 4742bf2220SShuo Chen ts.tv_nsec = static_cast<long>( 4842bf2220SShuo Chen (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000); 4942bf2220SShuo Chen return ts; 5042bf2220SShuo Chen} 5142bf2220SShuo Chen 5242bf2220SShuo Chenvoid readTimerfd(int timerfd, Timestamp now) 5342bf2220SShuo Chen{ 5442bf2220SShuo Chen uint64_t howmany; 5542bf2220SShuo Chen ssize_t n = ::read(timerfd, &howmany, sizeof howmany); 5642bf2220SShuo Chen LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); 5742bf2220SShuo Chen if (n != sizeof howmany) 5842bf2220SShuo Chen { 5942bf2220SShuo Chen LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8"; 6042bf2220SShuo Chen } 6142bf2220SShuo Chen} 6242bf2220SShuo Chen 6342bf2220SShuo Chenvoid resetTimerfd(int timerfd, Timestamp expiration) 6442bf2220SShuo Chen{ 6542bf2220SShuo Chen // wake up loop by timerfd_settime() 6642bf2220SShuo Chen struct itimerspec newValue; 6742bf2220SShuo Chen struct itimerspec oldValue; 6842bf2220SShuo Chen bzero(&newValue, sizeof newValue); 6942bf2220SShuo Chen bzero(&oldValue, sizeof oldValue); 7042bf2220SShuo Chen newValue.it_value = howMuchTimeFromNow(expiration); 7142bf2220SShuo Chen int ret = timerfd_settime(timerfd, 0, &newValue, &oldValue); 7242bf2220SShuo Chen if (ret) 7342bf2220SShuo Chen { 7442bf2220SShuo Chen LOG_SYSERR << "timerfd_settime()"; 7542bf2220SShuo Chen } 7642bf2220SShuo Chen} 7742bf2220SShuo Chen 7842bf2220SShuo Chen} 7942bf2220SShuo Chen} 8042bf2220SShuo Chen 8142bf2220SShuo Chenusing namespace muduo; 8242bf2220SShuo Chenusing namespace muduo::detail; 8342bf2220SShuo Chen 8442bf2220SShuo ChenTimerQueue::TimerQueue(EventLoop* loop) 8542bf2220SShuo Chen : loop_(loop), 8642bf2220SShuo Chen timerfd_(createTimerfd()), 8742bf2220SShuo Chen timerfdChannel_(loop, timerfd_), 8842bf2220SShuo Chen timers_() 8942bf2220SShuo Chen{ 9042bf2220SShuo Chen timerfdChannel_.setReadCallback( 9142bf2220SShuo Chen boost::bind(&TimerQueue::handleRead, this)); 9242bf2220SShuo Chen // we are always reading the timerfd, we disarm it with timerfd_settime. 9342bf2220SShuo Chen timerfdChannel_.enableReading(); 9442bf2220SShuo Chen} 9542bf2220SShuo Chen 9642bf2220SShuo ChenTimerQueue::~TimerQueue() 9742bf2220SShuo Chen{ 9842bf2220SShuo Chen ::close(timerfd_); 9942bf2220SShuo Chen // do not remove channel, since we're in EventLoop::dtor(); 10042bf2220SShuo Chen for (TimerList::iterator it = timers_.begin(); 10142bf2220SShuo Chen it != timers_.end(); ++it) 10242bf2220SShuo Chen { 10342bf2220SShuo Chen delete it->second; 10442bf2220SShuo Chen } 10542bf2220SShuo Chen} 10642bf2220SShuo Chen 10742bf2220SShuo ChenTimerId TimerQueue::addTimer(const TimerCallback& cb, 10842bf2220SShuo Chen Timestamp when, 10942bf2220SShuo Chen double interval) 11042bf2220SShuo Chen{ 11142bf2220SShuo Chen Timer* timer = new Timer(cb, when, interval); 11242bf2220SShuo Chen loop_->assertInLoopThread(); 11342bf2220SShuo Chen bool earliestChanged = insert(timer); 11442bf2220SShuo Chen 11542bf2220SShuo Chen if (earliestChanged) 11642bf2220SShuo Chen { 11742bf2220SShuo Chen resetTimerfd(timerfd_, timer->expiration()); 11842bf2220SShuo Chen } 11942bf2220SShuo Chen return TimerId(timer); 12042bf2220SShuo Chen} 12142bf2220SShuo Chen 12242bf2220SShuo Chenvoid TimerQueue::handleRead() 12342bf2220SShuo Chen{ 12442bf2220SShuo Chen loop_->assertInLoopThread(); 12542bf2220SShuo Chen Timestamp now(Timestamp::now()); 12642bf2220SShuo Chen readTimerfd(timerfd_, now); 12742bf2220SShuo Chen 12842bf2220SShuo Chen std::vector<Entry> expired = getExpired(now); 12942bf2220SShuo Chen 13042bf2220SShuo Chen // safe to callback outside critical section 13142bf2220SShuo Chen for (std::vector<Entry>::iterator it = expired.begin(); 13242bf2220SShuo Chen it != expired.end(); ++it) 13342bf2220SShuo Chen { 13442bf2220SShuo Chen it->second->run(); 13542bf2220SShuo Chen } 13642bf2220SShuo Chen 13742bf2220SShuo Chen reset(expired, now); 13842bf2220SShuo Chen} 13942bf2220SShuo Chen 14042bf2220SShuo Chenstd::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now) 14142bf2220SShuo Chen{ 14242bf2220SShuo Chen std::vector<Entry> expired; 14342bf2220SShuo Chen Entry sentry = std::make_pair(now, reinterpret_cast<Timer*>(UINTPTR_MAX)); 14442bf2220SShuo Chen TimerList::iterator it = timers_.lower_bound(sentry); 14542bf2220SShuo Chen assert(it == timers_.end() || now < it->first); 14642bf2220SShuo Chen std::copy(timers_.begin(), it, back_inserter(expired)); 14742bf2220SShuo Chen timers_.erase(timers_.begin(), it); 14842bf2220SShuo Chen 14942bf2220SShuo Chen return expired; 15042bf2220SShuo Chen} 15142bf2220SShuo Chen 15242bf2220SShuo Chenvoid TimerQueue::reset(const std::vector<Entry>& expired, Timestamp now) 15342bf2220SShuo Chen{ 15442bf2220SShuo Chen Timestamp nextExpire; 15542bf2220SShuo Chen 15642bf2220SShuo Chen for (std::vector<Entry>::const_iterator it = expired.begin(); 15742bf2220SShuo Chen it != expired.end(); ++it) 15842bf2220SShuo Chen { 15942bf2220SShuo Chen if (it->second->repeat()) 16042bf2220SShuo Chen { 16142bf2220SShuo Chen it->second->restart(now); 16242bf2220SShuo Chen insert(it->second); 16342bf2220SShuo Chen } 16442bf2220SShuo Chen else 16542bf2220SShuo Chen { 16642bf2220SShuo Chen // FIXME move to a free list 16742bf2220SShuo Chen delete it->second; 16842bf2220SShuo Chen } 16942bf2220SShuo Chen } 17042bf2220SShuo Chen 17142bf2220SShuo Chen if (!timers_.empty()) 17242bf2220SShuo Chen { 17342bf2220SShuo Chen nextExpire = timers_.begin()->second->expiration(); 17442bf2220SShuo Chen } 17542bf2220SShuo Chen 17642bf2220SShuo Chen if (nextExpire.valid()) 17742bf2220SShuo Chen { 17842bf2220SShuo Chen resetTimerfd(timerfd_, nextExpire); 17942bf2220SShuo Chen } 18042bf2220SShuo Chen} 18142bf2220SShuo Chen 18242bf2220SShuo Chenbool TimerQueue::insert(Timer* timer) 18342bf2220SShuo Chen{ 18442bf2220SShuo Chen bool earliestChanged = false; 18542bf2220SShuo Chen Timestamp when = timer->expiration(); 18642bf2220SShuo Chen TimerList::iterator it = timers_.begin(); 18742bf2220SShuo Chen if (it == timers_.end() || when < it->first) 18842bf2220SShuo Chen { 18942bf2220SShuo Chen earliestChanged = true; 19042bf2220SShuo Chen } 19142bf2220SShuo Chen std::pair<TimerList::iterator, bool> result = timers_.insert(std::make_pair(when, timer)); 19242bf2220SShuo Chen assert(result.second); 19342bf2220SShuo Chen return earliestChanged; 19442bf2220SShuo Chen} 19542bf2220SShuo Chen 196