1cc7f415cSShuo Chen// excerpts from http://code.google.com/p/muduo/ 2cc7f415cSShuo Chen// 3cc7f415cSShuo Chen// Use of this source code is governed by a BSD-style license 4cc7f415cSShuo Chen// that can be found in the License file. 5cc7f415cSShuo Chen// 6cc7f415cSShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com) 7cc7f415cSShuo Chen 8cc7f415cSShuo Chen#define __STDC_LIMIT_MACROS 9cc7f415cSShuo Chen#include "TimerQueue.h" 10cc7f415cSShuo Chen 11cc7f415cSShuo Chen#include "logging/Logging.h" 12cc7f415cSShuo Chen#include "EventLoop.h" 13cc7f415cSShuo Chen#include "Timer.h" 14cc7f415cSShuo Chen#include "TimerId.h" 15cc7f415cSShuo Chen 16cc7f415cSShuo Chen#include <boost/bind.hpp> 17cc7f415cSShuo Chen 18cc7f415cSShuo Chen#include <sys/timerfd.h> 19cc7f415cSShuo Chen 20cc7f415cSShuo Chennamespace muduo 21cc7f415cSShuo Chen{ 22cc7f415cSShuo Chennamespace detail 23cc7f415cSShuo Chen{ 24cc7f415cSShuo Chen 25cc7f415cSShuo Chenint createTimerfd() 26cc7f415cSShuo Chen{ 27cc7f415cSShuo Chen int timerfd = ::timerfd_create(CLOCK_MONOTONIC, 28cc7f415cSShuo Chen TFD_NONBLOCK | TFD_CLOEXEC); 29cc7f415cSShuo Chen if (timerfd < 0) 30cc7f415cSShuo Chen { 31cc7f415cSShuo Chen LOG_SYSFATAL << "Failed in timerfd_create"; 32cc7f415cSShuo Chen } 33cc7f415cSShuo Chen return timerfd; 34cc7f415cSShuo Chen} 35cc7f415cSShuo Chen 36cc7f415cSShuo Chenstruct timespec howMuchTimeFromNow(Timestamp when) 37cc7f415cSShuo Chen{ 38cc7f415cSShuo Chen int64_t microseconds = when.microSecondsSinceEpoch() 39cc7f415cSShuo Chen - Timestamp::now().microSecondsSinceEpoch(); 40cc7f415cSShuo Chen if (microseconds < 100) 41cc7f415cSShuo Chen { 42cc7f415cSShuo Chen microseconds = 100; 43cc7f415cSShuo Chen } 44cc7f415cSShuo Chen struct timespec ts; 45cc7f415cSShuo Chen ts.tv_sec = static_cast<time_t>( 46cc7f415cSShuo Chen microseconds / Timestamp::kMicroSecondsPerSecond); 47cc7f415cSShuo Chen ts.tv_nsec = static_cast<long>( 48cc7f415cSShuo Chen (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000); 49cc7f415cSShuo Chen return ts; 50cc7f415cSShuo Chen} 51cc7f415cSShuo Chen 52cc7f415cSShuo Chenvoid readTimerfd(int timerfd, Timestamp now) 53cc7f415cSShuo Chen{ 54cc7f415cSShuo Chen uint64_t howmany; 55cc7f415cSShuo Chen ssize_t n = ::read(timerfd, &howmany, sizeof howmany); 56cc7f415cSShuo Chen LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); 57cc7f415cSShuo Chen if (n != sizeof howmany) 58cc7f415cSShuo Chen { 59cc7f415cSShuo Chen LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8"; 60cc7f415cSShuo Chen } 61cc7f415cSShuo Chen} 62cc7f415cSShuo Chen 63cc7f415cSShuo Chenvoid resetTimerfd(int timerfd, Timestamp expiration) 64cc7f415cSShuo Chen{ 65cc7f415cSShuo Chen // wake up loop by timerfd_settime() 66cc7f415cSShuo Chen struct itimerspec newValue; 67cc7f415cSShuo Chen struct itimerspec oldValue; 68cc7f415cSShuo Chen bzero(&newValue, sizeof newValue); 69cc7f415cSShuo Chen bzero(&oldValue, sizeof oldValue); 70cc7f415cSShuo Chen newValue.it_value = howMuchTimeFromNow(expiration); 71b4a5ce52SShuo Chen int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue); 72cc7f415cSShuo Chen if (ret) 73cc7f415cSShuo Chen { 74cc7f415cSShuo Chen LOG_SYSERR << "timerfd_settime()"; 75cc7f415cSShuo Chen } 76cc7f415cSShuo Chen} 77cc7f415cSShuo Chen 78cc7f415cSShuo Chen} 79cc7f415cSShuo Chen} 80cc7f415cSShuo Chen 81cc7f415cSShuo Chenusing namespace muduo; 82cc7f415cSShuo Chenusing namespace muduo::detail; 83cc7f415cSShuo Chen 84cc7f415cSShuo ChenTimerQueue::TimerQueue(EventLoop* loop) 85cc7f415cSShuo Chen : loop_(loop), 86cc7f415cSShuo Chen timerfd_(createTimerfd()), 87cc7f415cSShuo Chen timerfdChannel_(loop, timerfd_), 88cc7f415cSShuo Chen timers_() 89cc7f415cSShuo Chen{ 90cc7f415cSShuo Chen timerfdChannel_.setReadCallback( 91cc7f415cSShuo Chen boost::bind(&TimerQueue::handleRead, this)); 92cc7f415cSShuo Chen // we are always reading the timerfd, we disarm it with timerfd_settime. 93cc7f415cSShuo Chen timerfdChannel_.enableReading(); 94cc7f415cSShuo Chen} 95cc7f415cSShuo Chen 96cc7f415cSShuo ChenTimerQueue::~TimerQueue() 97cc7f415cSShuo Chen{ 98cc7f415cSShuo Chen ::close(timerfd_); 99cc7f415cSShuo Chen // do not remove channel, since we're in EventLoop::dtor(); 100cc7f415cSShuo Chen for (TimerList::iterator it = timers_.begin(); 101cc7f415cSShuo Chen it != timers_.end(); ++it) 102cc7f415cSShuo Chen { 103cc7f415cSShuo Chen delete it->second; 104cc7f415cSShuo Chen } 105cc7f415cSShuo Chen} 106cc7f415cSShuo Chen 107cc7f415cSShuo ChenTimerId TimerQueue::addTimer(const TimerCallback& cb, 108cc7f415cSShuo Chen Timestamp when, 109cc7f415cSShuo Chen double interval) 110cc7f415cSShuo Chen{ 111cc7f415cSShuo Chen Timer* timer = new Timer(cb, when, interval); 112c461658bSShuo Chen loop_->runInLoop( 113344a2ce1SShuo Chen boost::bind(&TimerQueue::addTimerInLoop, this, timer)); 114c461658bSShuo Chen return TimerId(timer); 115c461658bSShuo Chen} 116c461658bSShuo Chen 117344a2ce1SShuo Chenvoid TimerQueue::addTimerInLoop(Timer* timer) 118c461658bSShuo Chen{ 119cc7f415cSShuo Chen loop_->assertInLoopThread(); 120cc7f415cSShuo Chen bool earliestChanged = insert(timer); 121cc7f415cSShuo Chen 122cc7f415cSShuo Chen if (earliestChanged) 123cc7f415cSShuo Chen { 124cc7f415cSShuo Chen resetTimerfd(timerfd_, timer->expiration()); 125cc7f415cSShuo Chen } 126cc7f415cSShuo Chen} 127cc7f415cSShuo Chen 128cc7f415cSShuo Chenvoid TimerQueue::handleRead() 129cc7f415cSShuo Chen{ 130cc7f415cSShuo Chen loop_->assertInLoopThread(); 131cc7f415cSShuo Chen Timestamp now(Timestamp::now()); 132cc7f415cSShuo Chen readTimerfd(timerfd_, now); 133cc7f415cSShuo Chen 134cc7f415cSShuo Chen std::vector<Entry> expired = getExpired(now); 135cc7f415cSShuo Chen 136cc7f415cSShuo Chen // safe to callback outside critical section 137cc7f415cSShuo Chen for (std::vector<Entry>::iterator it = expired.begin(); 138cc7f415cSShuo Chen it != expired.end(); ++it) 139cc7f415cSShuo Chen { 140cc7f415cSShuo Chen it->second->run(); 141cc7f415cSShuo Chen } 142cc7f415cSShuo Chen 143cc7f415cSShuo Chen reset(expired, now); 144cc7f415cSShuo Chen} 145cc7f415cSShuo Chen 146cc7f415cSShuo Chenstd::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now) 147cc7f415cSShuo Chen{ 148cc7f415cSShuo Chen std::vector<Entry> expired; 149cc7f415cSShuo Chen Entry sentry = std::make_pair(now, reinterpret_cast<Timer*>(UINTPTR_MAX)); 150cc7f415cSShuo Chen TimerList::iterator it = timers_.lower_bound(sentry); 151cc7f415cSShuo Chen assert(it == timers_.end() || now < it->first); 152cc7f415cSShuo Chen std::copy(timers_.begin(), it, back_inserter(expired)); 153cc7f415cSShuo Chen timers_.erase(timers_.begin(), it); 154cc7f415cSShuo Chen 155cc7f415cSShuo Chen return expired; 156cc7f415cSShuo Chen} 157cc7f415cSShuo Chen 158cc7f415cSShuo Chenvoid TimerQueue::reset(const std::vector<Entry>& expired, Timestamp now) 159cc7f415cSShuo Chen{ 160cc7f415cSShuo Chen Timestamp nextExpire; 161cc7f415cSShuo Chen 162cc7f415cSShuo Chen for (std::vector<Entry>::const_iterator it = expired.begin(); 163cc7f415cSShuo Chen it != expired.end(); ++it) 164cc7f415cSShuo Chen { 165cc7f415cSShuo Chen if (it->second->repeat()) 166cc7f415cSShuo Chen { 167cc7f415cSShuo Chen it->second->restart(now); 168cc7f415cSShuo Chen insert(it->second); 169cc7f415cSShuo Chen } 170cc7f415cSShuo Chen else 171cc7f415cSShuo Chen { 172cc7f415cSShuo Chen // FIXME move to a free list 173cc7f415cSShuo Chen delete it->second; 174cc7f415cSShuo Chen } 175cc7f415cSShuo Chen } 176cc7f415cSShuo Chen 177cc7f415cSShuo Chen if (!timers_.empty()) 178cc7f415cSShuo Chen { 179cc7f415cSShuo Chen nextExpire = timers_.begin()->second->expiration(); 180cc7f415cSShuo Chen } 181cc7f415cSShuo Chen 182cc7f415cSShuo Chen if (nextExpire.valid()) 183cc7f415cSShuo Chen { 184cc7f415cSShuo Chen resetTimerfd(timerfd_, nextExpire); 185cc7f415cSShuo Chen } 186cc7f415cSShuo Chen} 187cc7f415cSShuo Chen 188cc7f415cSShuo Chenbool TimerQueue::insert(Timer* timer) 189cc7f415cSShuo Chen{ 190cc7f415cSShuo Chen bool earliestChanged = false; 191cc7f415cSShuo Chen Timestamp when = timer->expiration(); 192cc7f415cSShuo Chen TimerList::iterator it = timers_.begin(); 193cc7f415cSShuo Chen if (it == timers_.end() || when < it->first) 194cc7f415cSShuo Chen { 195cc7f415cSShuo Chen earliestChanged = true; 196cc7f415cSShuo Chen } 197a20e676dSShuo Chen std::pair<TimerList::iterator, bool> result = 198a20e676dSShuo Chen timers_.insert(std::make_pair(when, timer)); 199cc7f415cSShuo Chen assert(result.second); 200cc7f415cSShuo Chen return earliestChanged; 201cc7f415cSShuo Chen} 202cc7f415cSShuo Chen 203